1 #include "Global.h"
2 
3 #include "MainWindow.h"
4 #include "MapView.h"
5 #include "ImageMapLayer.h"
6 
7 #include "Document.h"
8 #include "MerkaartorPreferences.h"
9 #include "Projection.h"
10 
11 #include "IMapAdapterFactory.h"
12 #include "IMapAdapter.h"
13 #include "imagemanager.h"
14 #ifdef USE_WEBKIT
15 #include "browserimagemanager.h"
16 #endif
17 #include "tilemapadapter.h"
18 #include "wmsmapadapter.h"
19 #include "WmscMapAdapter.h"
20 
21 #include <QLocale>
22 #include <QPainter>
23 #include <QMessageBox>
24 
25 #include "LayerWidget.h"
26 #include "Features.h"
27 
28 #include "ui_LicenseDisplayDialog.h"
29 
30 // ImageMapLayerPrivate
31 
32 class ImageMapLayerPrivate
33 {
34 public:
35     QUuid bgType;
36     IMapAdapter* theMapAdapter;
37 
38     QPixmap curPix;
39     QPixmap newPix;
40     Projection theProjection;
41     QString selServer;
42 
43     IImageManager* theImageManager;
44 #ifdef USE_WEBKIT
45     BrowserImageManager* theBrowserImageManager;
46 #endif
47     ImageManager* theNetworkImageManager;
48 
49     QRect pr;
50     QTransform theTransform;
51     QRectF Viewport;
52     QTransform AlignementTransform;
53     QVector<QTransform> AlignementTransformList;
54     QPointF cumulatedDelta;
55 
56 public:
ImageMapLayerPrivate()57     ImageMapLayerPrivate()
58     {
59         theMapAdapter = NULL;
60         theImageManager = NULL;
61 #ifdef USE_WEBKIT
62         theBrowserImageManager = NULL;
63 #endif
64         theNetworkImageManager = NULL;
65     }
~ImageMapLayerPrivate()66     ~ImageMapLayerPrivate()
67     {
68         delete theMapAdapter;
69         delete theImageManager;
70     }
71 };
72 
73 
74 // ImageMapLayer
75 
ImageMapLayer(const QString & aName)76 ImageMapLayer::ImageMapLayer(const QString & aName)
77     : Layer(aName), p(new ImageMapLayerPrivate)
78 {
79     p->bgType = NONE_ADAPTER_UUID;
80     setName(tr("Map - None"));
81     Layer::setVisible(false);
82     setReadonly(true);
83 }
84 
~ImageMapLayer()85 ImageMapLayer::~ ImageMapLayer()
86 {
87     delete p;
88 }
89 
boundingBox()90 CoordBox ImageMapLayer::boundingBox()
91 {
92     if (p->bgType == SHAPE_ADAPTER_UUID && isVisible())
93         return Layer::boundingBox();
94     else
95         if (!p->theMapAdapter || p->theMapAdapter->getBoundingbox().isNull())
96             return CoordBox();
97 
98     p->theProjection.setProjectionType(p->theMapAdapter->projection());
99     QRectF r = p->theMapAdapter->getBoundingbox();
100     Coord tl = p->theProjection.inverse(r.topLeft());
101     Coord br = p->theProjection.inverse(r.bottomRight());
102     return CoordBox(tl, br);
103 }
104 
size() const105 int ImageMapLayer::size() const
106 {
107     return Layer::size();
108 }
109 
newWidget(void)110 LayerWidget* ImageMapLayer::newWidget(void)
111 {
112 //	delete theWidget;
113     theWidget = new ImageLayerWidget(this);
114     return theWidget;
115 }
116 
setEnabled(bool b)117 void ImageMapLayer::setEnabled(bool b)
118 {
119     if (!b)
120         setMapAdapter(NONE_ADAPTER_UUID);
121 
122     Layer::setEnabled(b);
123 }
124 
updateWidget()125 void ImageMapLayer::updateWidget()
126 {
127     theWidget->initActions();
128     setMapAdapter(M_PREFS->getBackgroundPlugin(), M_PREFS->getSelectedServer());
129     theWidget->update();
130 }
131 
setVisible(bool b)132 void ImageMapLayer::setVisible(bool b)
133 {
134     Layer::setVisible(b);
135     if (p->bgType == NONE_ADAPTER_UUID)
136         Layer::setVisible(false);
137     M_PREFS->setBgVisible(isVisible());
138 }
139 
resetAlign()140 void ImageMapLayer::resetAlign()
141 {
142     p->AlignementTransform = QTransform();
143     if (p->theMapAdapter) {
144         if (p->theMapAdapter->isTiled())
145             p->AlignementTransformList[p->theMapAdapter->getAdaptedZoom()] = QTransform();
146         else
147             p->AlignementTransformList[0] = QTransform();
148     } else
149         p->AlignementTransformList.resize(0);
150 }
151 
projection() const152 QString ImageMapLayer::projection() const
153 {
154     if (p->theMapAdapter)
155         return p->theMapAdapter->projection();
156 
157     return QString();
158 }
159 
getImageManger()160 IImageManager* ImageMapLayer::getImageManger()
161 {
162     return p->theImageManager;
163 }
164 
getMapAdapter()165 IMapAdapter* ImageMapLayer::getMapAdapter()
166 {
167     return p->theMapAdapter;
168 }
169 
setNoneAdapter()170 void ImageMapLayer::setNoneAdapter()
171 {
172     p->bgType = NONE_ADAPTER_UUID;
173     setName(tr("Map - None"));
174     setVisible(false);
175 }
176 
setMapAdapter(const QUuid & theAdapterUid,const QString & server)177 void ImageMapLayer::setMapAdapter(const QUuid& theAdapterUid, const QString& server)
178 {
179     WmsServerList* wsl;
180     TmsServerList* tsl;
181 
182     if (p->theImageManager)
183         p->theImageManager->abortLoading();
184     p->theImageManager = NULL;
185     on_loadingFinished();
186     if (p->theMapAdapter)
187         SAFE_DELETE(p->theMapAdapter);
188     p->curPix = QPixmap();
189     resetAlign();
190 
191     QString id = theAdapterUid.toString();
192     p->bgType = theAdapterUid;
193     M_PREFS->setBackgroundPlugin(theAdapterUid);
194     if (p->bgType == NONE_ADAPTER_UUID) {
195         setNoneAdapter();
196     } else
197     if (p->bgType == WMS_ADAPTER_UUID) {
198         wsl = M_PREFS->getWmsServers();
199         if (!wsl->contains(server)) {  // WMS not locally found
200             setNoneAdapter();
201         } else {
202             p->selServer = server;
203             WmsServer theWmsServer(wsl->value(p->selServer));
204             p->theMapAdapter = new WMSMapAdapter(theWmsServer);
205             switch (theWmsServer.WmsIsTiled) {
206             case 0:
207                 setName(tr("Map - WMS - %1").arg(p->theMapAdapter->getName()));
208                 break;
209             case 1:
210                 setName(tr("Map - WMS-C - %1").arg(p->theMapAdapter->getName()));
211                 break;
212             case 2:
213                 setName(tr("Map - WMS-Tiled - %1").arg(p->theMapAdapter->getName()));
214                 break;
215             }
216             id += p->theMapAdapter->getName();
217         }
218     } else
219     if (p->bgType == TMS_ADAPTER_UUID) {
220         tsl = M_PREFS->getTmsServers();
221         if (!tsl->contains(server)) {  // TMS not locally found
222             setNoneAdapter();
223         } else {
224             p->selServer = server;
225             TmsServer ts = tsl->value(p->selServer);
226             p->theMapAdapter = new TileMapAdapter(ts);
227 
228             setName(tr("Map - TMS - %1").arg(p->theMapAdapter->getName()));
229             id += p->theMapAdapter->getName();
230         }
231     } else
232     if (p->bgType == SHAPE_ADAPTER_UUID) {
233         setNoneAdapter();
234     } else
235     {
236         IMapAdapterFactory* fac = M_PREFS->getBackgroundPlugin(p->bgType);
237         if (fac)
238             p->theMapAdapter = fac->CreateInstance();
239         if (p->theMapAdapter) {
240             setName(tr("Map - %1").arg(p->theMapAdapter->getName()));
241             p->theMapAdapter->setSettings(M_PREFS->getQSettings());
242             ImageLayerWidget* theImageWidget = qobject_cast<ImageLayerWidget*>(theWidget);
243             Q_ASSERT(theImageWidget);
244             connect(p->theMapAdapter, SIGNAL(forceZoom()), theImageWidget, SLOT(zoomLayer()));
245             connect(p->theMapAdapter, SIGNAL(forceProjection()), theImageWidget, SLOT(setProjection()));
246 #ifndef _MOBILE
247             if (g_Merk_MainWindow)
248                 connect(p->theMapAdapter, SIGNAL(forceRefresh()), g_Merk_MainWindow, SLOT(invalidateView()));
249 #endif
250         } else
251             setNoneAdapter();
252     }
253     // Display License
254     if (p->theMapAdapter) {
255         QString s = p->theMapAdapter->getLicenseUrl();
256         if (!s.isEmpty()) {
257             QSettings* set = M_PREFS->getQSettings();
258             QStringList AcceptedLicenses = set->value("backgroundImage/AcceptedLicenses").toStringList();
259             if (!AcceptedLicenses.contains(id)) {
260                 QUrl u(s);
261                 if (u.isValid()) {
262                     Ui::LicenseDisplayDialog ui;
263                     QDialog dlg;
264                     ui.setupUi(&dlg);
265                     dlg.setWindowTitle(tr("Licensing Terms: %1").arg(name()));
266                     ui.urlLabel->setText(QString("<a href='%1'>%2</a>").arg(u.toString()).arg(u.toString()));
267 
268                     bool OK = false;
269                     while (!OK) {
270                         if (dlg.exec()) {
271                             if (!ui.cbAgree->isChecked()) {
272                                 QMessageBox::StandardButton ret = QMessageBox::warning(&dlg, tr("License Terms not accepted"), tr("You have not ticked the checkbox expressing your agreement with the licensing terms.\nAs such, you won't be able to use this source as a map layer.\nIs it really what you meant?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
273                                 if (ret == QMessageBox::Yes)
274                                     OK = true;
275                             } else
276                                 OK = true;
277                         }
278                     }
279                     if (!ui.cbAgree->isChecked()) {
280                         SAFE_DELETE(p->theMapAdapter)
281                         if (p->theImageManager)
282                             p->theImageManager->abortLoading();
283                         SAFE_DELETE(p->theImageManager)
284                         on_loadingFinished();
285                         p->curPix = QPixmap();
286 
287                         p->bgType = NONE_ADAPTER_UUID;
288                         setName(tr("Map - None"));
289                         setVisible(false);
290                     } else {
291                         AcceptedLicenses << id;
292                         set->setValue("backgroundImage/AcceptedLicenses", AcceptedLicenses);
293                     }
294                 }
295             }
296         }
297     }
298     if (p->theMapAdapter) {
299         switch (p->theMapAdapter->getType()) {
300             case IMapAdapter::DirectBackground:
301             case IMapAdapter::VectorBackground:
302                 if (!p->theNetworkImageManager) {
303                     p->theNetworkImageManager = new ImageManager();
304                     connect(p->theNetworkImageManager, SIGNAL(dataRequested()),
305                             this, SLOT(on_imageRequested()), Qt::QueuedConnection);
306                     connect(p->theNetworkImageManager, SIGNAL(dataReceived()),
307                             this, SLOT(on_imageReceived()), Qt::QueuedConnection);
308                     connect(p->theNetworkImageManager, SIGNAL(loadingFinished()),
309                             this, SLOT(on_loadingFinished()), Qt::QueuedConnection);
310                 }
311                 p->theImageManager = p->theNetworkImageManager;
312                 p->theMapAdapter->setImageManager(p->theImageManager);
313                 break;
314             case IMapAdapter::BrowserBackground :
315 #ifdef USE_WEBKIT
316                 if (!p->theBrowserImageManager) {
317                     p->theBrowserImageManager = new BrowserImageManager();
318                     connect(p->theBrowserImageManager, SIGNAL(dataRequested()),
319                         this, SLOT(on_imageRequested()), Qt::QueuedConnection);
320                     connect(p->theBrowserImageManager, SIGNAL(dataReceived()),
321                         this, SLOT(on_imageReceived()), Qt::QueuedConnection);
322                     connect(p->theBrowserImageManager, SIGNAL(loadingFinished()),
323                         this, SLOT(on_loadingFinished()), Qt::QueuedConnection);
324                 }
325                 p->theBrowserImageManager->setCacheDir(M_PREFS->getCacheDir());
326                 p->theBrowserImageManager->setCacheMaxSize(M_PREFS->getCacheSize());
327                 #ifdef BROWSERIMAGEMANAGER_IS_THREADED
328                     m->start();
329                 #endif // BROWSERIMAGEMANAGER_IS_THREADED
330                 p->theImageManager = p->theBrowserImageManager;
331                 p->theMapAdapter->setImageManager(p->theImageManager);
332 #endif
333                 break;
334             case IMapAdapter::NetworkBackground :
335             case IMapAdapter::NetworkDataBackground :
336                 if (!p->theNetworkImageManager) {
337                     p->theNetworkImageManager = new ImageManager();
338                     connect(p->theNetworkImageManager, SIGNAL(dataRequested()),
339                         this, SLOT(on_imageRequested()), Qt::QueuedConnection);
340                     connect(p->theNetworkImageManager, SIGNAL(dataReceived()),
341                         this, SLOT(on_imageReceived()), Qt::QueuedConnection);
342                     connect(p->theNetworkImageManager, SIGNAL(loadingFinished()),
343                         this, SLOT(on_loadingFinished()), Qt::QueuedConnection);
344                 }
345                 p->theNetworkImageManager->setCacheDir(M_PREFS->getCacheDir());
346                 p->theNetworkImageManager->setCacheMaxSize(M_PREFS->getCacheSize());
347                 p->theImageManager = p->theNetworkImageManager;
348                 p->theMapAdapter->setImageManager(p->theImageManager);
349                 break;
350         }
351     }
352 }
353 
isTiled()354 bool ImageMapLayer::isTiled()
355 {
356     if (!p->theMapAdapter)
357         return false;
358 
359     return (p->theMapAdapter->isTiled());
360 }
361 
QTransformToXml(QXmlStreamWriter & stream,const QTransform & theTransform)362 void QTransformToXml(QXmlStreamWriter& stream, const QTransform& theTransform)
363 {
364     stream.writeAttribute("m11", QString::number(theTransform.m11()));
365     stream.writeAttribute("m12", QString::number(theTransform.m12()));
366     stream.writeAttribute("m13", QString::number(theTransform.m13()));
367     stream.writeAttribute("m21", QString::number(theTransform.m21()));
368     stream.writeAttribute("m22", QString::number(theTransform.m22()));
369     stream.writeAttribute("m23", QString::number(theTransform.m23()));
370     stream.writeAttribute("m31", QString::number(theTransform.m31()));
371     stream.writeAttribute("m32", QString::number(theTransform.m32()));
372     stream.writeAttribute("m33", QString::number(theTransform.m33()));
373 }
374 
QTransformFomXml(QXmlStreamReader & stream)375 QTransform QTransformFomXml(QXmlStreamReader& stream)
376 {
377     qreal m11 = stream.attributes().value("m11").toString().toDouble();
378     qreal m12 = stream.attributes().value("m12").toString().toDouble();
379     qreal m13 = stream.attributes().value("m13").toString().toDouble();
380     qreal m21 = stream.attributes().value("m21").toString().toDouble();
381     qreal m22 = stream.attributes().value("m11").toString().toDouble();
382     qreal m23 = stream.attributes().value("m23").toString().toDouble();
383     qreal m31 = stream.attributes().value("m31").toString().toDouble();
384     qreal m32 = stream.attributes().value("m32").toString().toDouble();
385     qreal m33 = stream.attributes().value("m33").toString().toDouble();
386 
387     return QTransform(m11, m12, m13, m21, m22, m23, m31, m32, m33);
388 }
389 
toXML(QXmlStreamWriter & stream,bool asTemplate,QProgressDialog *)390 bool ImageMapLayer::toXML(QXmlStreamWriter& stream, bool asTemplate, QProgressDialog * /* progress */)
391 {
392     stream.writeStartElement(metaObject()->className());
393 
394     stream.writeAttribute("xml:id", id());
395     stream.writeAttribute("name", name());
396     stream.writeAttribute("alpha", QString::number(getAlpha(),'f',2));
397     stream.writeAttribute("visible", QString((isVisible() ? "true" : "false")));
398     stream.writeAttribute("selected", QString((isSelected() ? "true" : "false")));
399     stream.writeAttribute("enabled", QString((isEnabled() ? "true" : "false")));
400 
401     stream.writeAttribute("bgtype", p->bgType.toString());
402 
403     WmsServer ws;
404     TmsServer ts;
405 
406     if (p->bgType == WMS_ADAPTER_UUID) {
407         stream.writeStartElement("WmsServer");
408         stream.writeAttribute("name", p->selServer);
409         stream.writeEndElement();
410     } else if (p->bgType == TMS_ADAPTER_UUID) {
411         stream.writeStartElement("TmsServer");
412         stream.writeAttribute("name", p->selServer);
413         stream.writeEndElement();
414     } else if (p->bgType != NONE_ADAPTER_UUID) {
415         stream.writeStartElement("Data");
416         if (!asTemplate)
417             p->theMapAdapter->toXML(stream);
418         stream.writeEndElement();
419     }
420     if (!asTemplate) {
421         stream.writeStartElement("AdjustmentList");
422         for (int i=0; i<p->AlignementTransformList.size(); ++i) {
423             if (!p->AlignementTransformList.at(i).isIdentity()) {
424                 stream.writeStartElement("Adjustment");
425                 stream.writeAttribute("zoom", QString::number(i));
426                 QTransformToXml(stream, p->AlignementTransformList.at(i));
427                 stream.writeEndElement();
428             }
429         }
430         stream.writeEndElement();
431     }
432     stream.writeEndElement();
433 
434     return true;
435 }
436 
fromXML(Document * d,QXmlStreamReader & stream,QProgressDialog *)437 ImageMapLayer * ImageMapLayer::fromXML(Document* d, QXmlStreamReader& stream, QProgressDialog * /*progress*/)
438 {
439     ImageMapLayer* l = new ImageMapLayer(stream.attributes().value("name").toString());
440 
441     l->setId(stream.attributes().value("xml:id").toString());
442     d->addImageLayer(l);
443 
444     QString server;
445     QUuid bgtype = QUuid(stream.attributes().value("bgtype").toString());
446 
447     qreal alpha = stream.attributes().value("alpha").toString().toDouble();
448     // TODO: Note that the logic for "enabled" is slightly different. Why?
449     bool visible = (stream.attributes().value("visible") == "true" ? true : false);
450     bool selected = (stream.attributes().value("selected") == "true" ? true : false);
451     bool enabled = (stream.attributes().value("enabled") == "false" ? false : true);
452 
453     stream.readNext();
454     while(!stream.atEnd() && !stream.isEndElement()) {
455         if (stream.name() == "AdjustmentList") {
456             stream.readNext();
457             while(!stream.atEnd() && !stream.isEndElement()) {
458                 if (stream.name() == "Adjustment") {
459                     int z = stream.attributes().value("zoom").toString().toInt();
460                     if (l->p->AlignementTransformList.size() < z+1)
461                         l->p->AlignementTransformList.resize(z+1);
462                     l->p->AlignementTransformList[z] = QTransformFomXml(stream);
463                     stream.readNext();
464                 } else if (!stream.isWhitespace()) {
465                     qDebug() << "ImgLay: logic error:" << stream.name() << ":" << stream.tokenType() << "(" << stream.lineNumber() << ")";
466                     stream.skipCurrentElement();
467                 }
468                 stream.readNext();
469             }
470         } else if (stream.name() == "WmsServer") {
471             server = stream.attributes().value("name").toString();
472             l->setMapAdapter(bgtype, server);
473             stream.readNext();
474         } else if (stream.name() == "TmsServer") {
475             server = stream.attributes().value("name").toString();
476             l->setMapAdapter(bgtype, server);
477             stream.readNext();
478         } else if (stream.name() == "Data") {
479             l->setMapAdapter(bgtype, server);
480             stream.readNext();
481             if (l->getMapAdapter())
482                 l->getMapAdapter()->fromXML(stream);
483         } else if (!stream.isWhitespace()) {
484             qDebug() << "ImgLay: logic error:" << stream.name() << ":" << stream.tokenType() << "(" << stream.lineNumber() << ")";
485             stream.skipCurrentElement();
486         }
487         stream.readNext();
488     }
489 
490     l->setAlpha(alpha);
491     l->setVisible(visible);
492     l->setSelected(selected);
493     l->setEnabled(enabled);
494 
495     return l;
496 }
497 
drawImage(QPainter * P)498 void ImageMapLayer::drawImage(QPainter* P)
499 {
500     if (!p->theMapAdapter)
501         return;
502 
503     P->setOpacity(getAlpha());
504     P->drawPixmap(0, 0, p->curPix);
505 }
506 
zoom(qreal zoom,const QPoint & pos,const QRect & rect)507 void ImageMapLayer::zoom(qreal zoom, const QPoint& pos, const QRect& rect)
508 {
509     if (!p->theMapAdapter)
510         return;
511     if (p->theMapAdapter->getImageManager())
512         p->theMapAdapter->getImageManager()->abortLoading();
513     if (p->curPix.isNull())
514         return;
515 
516     QPixmap tpm = p->curPix.scaled(rect.size() * zoom, Qt::KeepAspectRatio);
517     p->curPix.fill(Qt::transparent);
518     QPainter P(&p->curPix);
519     QPointF fPos(pos);
520     fPos -= fPos * zoom;
521     P.drawPixmap(fPos, tpm);
522 }
523 
pan(QPoint delta)524 void ImageMapLayer::pan(QPoint delta)
525 {
526     if (!p->theMapAdapter)
527         return;
528     if (p->theMapAdapter->getImageManager())
529         p->theMapAdapter->getImageManager()->abortLoading();
530     if (p->curPix.isNull())
531         return;
532 
533     QRegion exposed;
534     p->curPix.scroll(delta.x(), delta.y(), p->curPix.rect(), &exposed);
535     QPainter P(&p->curPix);
536     P.setClipping(true);
537     P.setClipRegion(exposed);
538     P.eraseRect(p->curPix.rect());
539     //        on_imageReceived();
540 }
541 
zoom_in()542 void ImageMapLayer::zoom_in()
543 {
544     if (!isTiled())
545         return;
546 
547     p->theMapAdapter->zoom_in();
548 }
549 
zoom_out()550 void ImageMapLayer::zoom_out()
551 {
552     if (!isTiled())
553         return;
554 
555     p->theMapAdapter->zoom_out();
556 }
557 
getCurrentZoom()558 int ImageMapLayer::getCurrentZoom()
559 {
560     if (!isTiled())
561         return -1;
562 
563     return p->theMapAdapter->getAdaptedZoom();
564 }
565 
setCurrentZoom(MapView & theView,const CoordBox & viewport,const QRect & rect)566 void ImageMapLayer::setCurrentZoom(MapView& theView, const CoordBox& viewport, const QRect& rect)
567 {
568     QRectF projVp;
569     QRectF fRect(rect);
570 
571     if (p->theProjection.getProjectionProj4() == theView.projection().getProjectionProj4()) {
572         projVp.setTopLeft(theView.invertedTransform().map(fRect.topLeft()));
573         projVp.setBottomRight(theView.invertedTransform().map(fRect.bottomRight()));
574     } else
575         projVp = p->theProjection.toProjectedRectF(viewport, rect);
576 
577     qreal tileWidth, tileHeight;
578     int maxZoom = p->theMapAdapter->getAdaptedMaxZoom(viewport);
579     int tilesizeW = p->theMapAdapter->getTileSizeW();
580     int tilesizeH = p->theMapAdapter->getTileSizeH();
581 
582     // Set zoom level to 0.
583     while (p->theMapAdapter->getAdaptedZoom()) {
584         p->theMapAdapter->zoom_out();
585     }
586 
587     tileWidth = p->theMapAdapter->getBoundingbox().width() / p->theMapAdapter->getTilesWE(p->theMapAdapter->getZoom());
588     tileHeight = p->theMapAdapter->getBoundingbox().height() / p->theMapAdapter->getTilesNS(p->theMapAdapter->getZoom());
589     qreal w = (fRect.width() / tilesizeW) * tileWidth;
590     qreal h = (fRect.height() / tilesizeH) * tileHeight;
591 
592     while (!(projVp.width() > w && -projVp.height() > h) && (p->theMapAdapter->getAdaptedZoom() < maxZoom)) {
593         p->theMapAdapter->zoom_in();
594 
595         tileWidth = p->theMapAdapter->getBoundingbox().width() / p->theMapAdapter->getTilesWE(p->theMapAdapter->getZoom());
596         tileHeight = p->theMapAdapter->getBoundingbox().height() / p->theMapAdapter->getTilesNS(p->theMapAdapter->getZoom());
597         w = (fRect.width() / tilesizeW) * tileWidth;
598         h = (fRect.height() / tilesizeH) * tileHeight;
599     }
600 
601     QPointF vpCenter = projVp.center();
602     QPointF upperLeft = QPointF(vpCenter.x() - w/2, vpCenter.y() + h/2);
603     QPointF lowerRight = QPointF(vpCenter.x() + w/2, vpCenter.y() - h/2);
604     QRectF vlm = QRectF(upperLeft, lowerRight);
605     if (p->theMapAdapter->getAdaptedZoom() && projVp != vlm)
606         p->theMapAdapter->zoom_out();
607 }
608 
pixelPerCoord()609 qreal ImageMapLayer::pixelPerCoord()
610 {
611     if (!isTiled())
612         return -1.;
613 
614     return (p->theMapAdapter->getTileSizeW() * p->theMapAdapter->getTilesWE(p->theMapAdapter->getZoom())) / 360.;
615 }
616 
forceRedraw(MapView & theView,QTransform & aTransform,QRect Screen)617 void ImageMapLayer::forceRedraw(MapView& theView, QTransform& aTransform, QRect Screen)
618 {
619     if (!p->theMapAdapter)
620         return;
621 
622     if (!p->Viewport.intersects(theView.viewport())) {
623         p->curPix = QPixmap(Screen.size());
624         p->curPix.fill(Qt::transparent);
625     }
626     p->AlignementTransform = aTransform;
627     p->Viewport = theView.viewport();
628 
629     draw(theView, Screen);
630 }
631 
draw(MapView & theView,QRect & rect)632 void ImageMapLayer::draw(MapView& theView, QRect& rect)
633 {
634     if (!p->theMapAdapter)
635         return;
636 
637     p->theProjection.setProjectionType(p->theMapAdapter->projection());
638     p->cumulatedDelta = QPointF();
639 
640     if (p->theMapAdapter->isTiled())
641         p->pr = drawTiled(theView, rect);
642     else
643         p->pr = drawFull(theView, rect);
644 
645     if (p->curPix.size() != rect.size()) {
646         p->curPix = QPixmap(rect.size());
647     }
648 
649     if (p->newPix.isNull())
650         return;
651 
652     const QSize ps = p->pr.size();
653     const QSize pmSize = p->newPix.size();
654     const qreal ratio = qMax<const qreal>((qreal)pmSize.width()/ps.width()*1.0, (qreal)pmSize.height()/ps.height()*1.0);
655 //    qDebug() << "Bg image ratio" << ratio;
656     QPixmap pms;
657     if (ratio >= 1.0) {
658 //        qDebug() << "Bg image scale 1" << ps << ":" << p->newPix.size();
659         pms = p->newPix.scaled(ps);
660     } else {
661         const QSizeF drawingSize = pmSize * ratio;
662         const QSizeF originSize = pmSize/2 - drawingSize/2;
663         const QPointF drawingOrigin = QPointF(originSize.width(), originSize.height());
664         const QRect drawingRect = QRect(drawingOrigin.toPoint(), drawingSize.toSize());
665 
666 //        qDebug() << "Bg image scale 2" << ps << ":" << p->newPix.size();
667         if (ps*ratio != drawingRect.size())
668             pms = p->newPix.copy(drawingRect).scaled(ps*ratio);
669         else
670             pms = p->newPix.copy(drawingRect);
671     }
672 
673     /* We need to clear the pixmap in case we're painting transparent stuff over */
674     p->curPix.fill(Qt::transparent);
675 
676     QPainter P(&p->curPix);
677     P.drawPixmap((pmSize.width()-pms.width())/2, (pmSize.height()-pms.height())/2, pms);
678     //    if (p->theMapAdapter->isTiled())
679     //        P.drawPixmap((pmSize.width()-pms.width())/2, (pmSize.height()-pms.height())/2, pms);
680     //    else
681     //        P.drawPixmap(QPoint((pmSize.width()-pms.width())/2, (pmSize.height()-pms.height())/2) + p->theDelta, pms);
682 }
683 
drawFull(MapView & theView,QRect & rect)684 QRect ImageMapLayer::drawFull(MapView& theView, QRect& rect)
685 {
686     QRectF fRect(rect);
687     p->AlignementTransformList.resize(1);
688     p->AlignementTransformList[0] *= p->AlignementTransform;
689     p->AlignementTransform = QTransform();
690     QRectF alignedViewport = p->AlignementTransformList.at(0).mapRect(p->Viewport);
691 
692     MapView::transformCalc(p->theTransform, p->theProjection, 0.0, CoordBox(alignedViewport), rect);
693 
694     CoordBox cViewport(p->theProjection.inverse(p->theTransform.inverted().map(fRect.bottomLeft())),
695                      p->theProjection.inverse(p->theTransform.inverted().map(fRect.topRight())));
696     CoordBox Viewport = CoordBox(p->AlignementTransformList.at(0).mapRect(cViewport));
697     QPointF bl = theView.toView(Viewport.bottomLeft());
698     QPointF tr = theView.toView(Viewport.topRight());
699 
700     if (
701             Viewport.bottomLeft().y() >= -90. && Viewport.bottomLeft().y() <= 90.
702             && Viewport.bottomLeft().x() >= -180. && Viewport.bottomLeft().x() <= 180.
703             && Viewport.topRight().y() >= -90. && Viewport.topRight().y() <= 90.
704             && Viewport.topRight().x() >= -180. && Viewport.topRight().x() <= 180.
705             ) {
706         QRectF vp;
707         if (p->theProjection.getProjectionProj4() == theView.projection().getProjectionProj4()  && alignedViewport == theView.viewport()) {
708             bl = QPointF(rect.bottomLeft());
709             tr = QPointF(rect.topRight());
710             vp.setTopLeft(theView.invertedTransform().map(fRect.topLeft()));
711             vp.setBottomRight(theView.invertedTransform().map(fRect.bottomRight()));
712         } else
713             vp = p->theProjection.toProjectedRectF(CoordBox(alignedViewport), rect);
714 
715         QRectF wgs84vp = QRectF(QPointF(Viewport.bottomLeft().x(), Viewport.bottomLeft().y())
716                                 , QPointF(Viewport.topRight().x(), Viewport.topRight().y()));
717 
718         // Act depending on adapter type
719         if (p->theMapAdapter->getType() == IMapAdapter::DirectBackground) {
720             QPixmap pm = p->theMapAdapter->getPixmap(wgs84vp, vp, rect);
721             if (!pm.isNull()) {
722                 p->curPix = QPixmap();
723                 if (pm.rect() != rect)
724                     p->newPix = pm.scaled(rect.size(), Qt::IgnoreAspectRatio);
725                 else
726                     p->newPix = pm;
727             } else
728                 return rect;
729         } else if (p->theMapAdapter->getType() == IMapAdapter::VectorBackground) {
730             const QList<IFeature*>* theFeatures = p->theMapAdapter->getPaths(wgs84vp, NULL);
731             if (theFeatures) {
732                 foreach(IFeature* f, *theFeatures) {
733                     const QPainterPath& thePath = f->getPath();
734                     if (thePath.elementCount() == 1) {
735                         IFeature::FId id(IFeature::Point, -(f->id().numId));
736                         if (get(id))
737                             continue;
738                         Node* N = g_backend.allocNode(this, Coord((QPointF)thePath.elementAt(0)));
739                         N->setId(id);
740                         add(N);
741                         for (int i=0; i<f->tagSize(); ++i)
742                             N->setTag(f->tagKey(i),f->tagValue(i));
743                     } else {
744                         IFeature::FId id(IFeature::LineString, -(f->id().numId));
745                         if (get(id))
746                             continue;
747                         Way* W = g_backend.allocWay(this);
748                         W->setId(id);
749                         for (int i=0; i<thePath.elementCount(); ++i) {
750                             Node* N = g_backend.allocNode(this, Coord((QPointF)thePath.elementAt(i)));
751                             add(N);
752                             W->add(N);
753                         }
754                         add(W);
755                         for (int i=0; i<f->tagSize(); ++i)
756                             W->setTag(f->tagKey(i),f->tagValue(i));
757                     }
758                 }
759             }
760             p->newPix = QPixmap(rect.size());
761             p->newPix.fill(Qt::transparent);
762         } else if (p->theMapAdapter->getType() == IMapAdapter::NetworkDataBackground) {
763 //            QString url (p->theMapAdapter->getQuery(wgs84vp, vp, rect));
764 //            if (!url.isEmpty()) {
765 //                qDebug() << "ImageMapLayer::drawFull: getting:" << url;
766 //                QByteArray ba = p->theMapAdapter->getImageManager()->getData(p->theMapAdapter,url);
767 //                QDomDocument* theXmlDoc = new QDomDocument();
768 //                theXmlDoc->setContent(ba);
769 //                Document* doc = Document::getDocumentFromXml(theXmlDoc);
770 //                if (doc) {
771 //                    QList<Feature*> theFeats;
772 //                    for (int i=0; i<doc->layerSize(); ++i)
773 //                        for (int j=0; j<doc->getLayer(i)->size(); ++j)
774 //                            if (!doc->getLayer(i)->get(j)->isNull())
775 //                                theFeats.push_back(doc->getLayer(i)->get(j));
776 //                    for (int i=0; i<theFeats.size(); ++i) {
777 //                        Feature*F = theFeats.at(i);
778 //                        // TODO Make reproducable id's or delete everything or ...
779 //                        if (get(F->id()))
780 //                            continue;
781 
782 //                        // get tags
783 //                        QList<QPair<QString, QString> > Tags;
784 //                        for (int j=0; j<F->tagSize(); ++j) {
785 //                            Tags << qMakePair(F->tagKey(j), F->tagValue(j));
786 //                        }
787 //                        F->clearTags();
788 
789 //                        // Re-link null features to the ones in the current document
790 //                        for (int j=0; j<F->size(); ++j) {
791 //                            Feature* C = F->get(j);
792 //                            if (C->isNull()) {
793 //                                if (Feature* CC = get(C->id())) {
794 //                                    if (Relation* R = CAST_RELATION(F)) {
795 //                                        QString role = R->getRole(j);
796 //                                        R->remove(j);
797 //                                        R->add(role, CC, j);
798 //                                    } else if (Way* W = CAST_WAY(F)) {
799 //                                        Node* N = CAST_NODE(CC);
800 //                                        W->remove(j);
801 //                                        W->add(N, j);
802 //                                    }
803 //                                } else
804 //                                    theFeats.push_back(C);
805 //                            }
806 //                        }
807 //                        F->layer()->remove(F);
808 //                        add(F);
809 
810 //                        //Put tags
811 //                        for (int j=0; j<Tags.size(); ++j) {
812 //                            F->setTag(Tags[j].first, Tags[j].second);
813 //                        }
814 //                    }
815 //                }
816 //                delete doc;
817 //                delete theXmlDoc;
818 //            }
819             p->newPix = QPixmap();
820             return rect;
821 
822         } else if (p->theMapAdapter->getType() == IMapAdapter::NetworkBackground || p->theMapAdapter->getType() == IMapAdapter::BrowserBackground) {
823             QString url (p->theMapAdapter->getQuery(wgs84vp, vp, rect));
824             if (!url.isEmpty()) {
825                 //qDebug() << "ImageMapLayer::drawFull: getting:" << url;
826                 QPixmap pm = QPixmap::fromImage(p->theMapAdapter->getImageManager()->getImage(p->theMapAdapter,url));
827                 if (!pm.isNull()) {
828                     p->curPix = QPixmap();
829                     p->newPix = pm.scaled(rect.size(), Qt::IgnoreAspectRatio);
830                 } else {
831                     p->newPix = QPixmap();
832                     return rect;
833                 }
834             }
835         }
836     }
837 
838     return QRectF(bl.x(), tr.y(), tr.x() - bl.x() +1, bl.y() - tr.y() + 1).toRect();
839 }
840 
drawTiled(MapView & theView,QRect & rect)841 QRect ImageMapLayer::drawTiled(MapView& theView, QRect& rect)
842 {
843     QRectF projVp;
844 //    QRectF fRect(-rect.width(), -rect.height(), rect.width()*3.0, rect.height()*3.0);
845     QRectF fRect(rect);
846 
847     if (p->theProjection.getProjectionProj4() == theView.projection().getProjectionProj4()) {
848         projVp.setTopLeft(theView.invertedTransform().map(fRect.topLeft()));
849         projVp.setBottomRight(theView.invertedTransform().map(fRect.bottomRight()));
850     } else
851         projVp = p->theProjection.toProjectedRectF(CoordBox(p->Viewport), fRect.toRect());
852 
853     qreal tileWidth, tileHeight;
854     int maxZoom = p->theMapAdapter->getAdaptedMaxZoom(p->Viewport);
855     int tilesizeW = p->theMapAdapter->getTileSizeW();
856     int tilesizeH = p->theMapAdapter->getTileSizeH();
857 
858     if (!M_PREFS->getZoomBoris()) {
859         // Set zoom level to 0.
860         while (p->theMapAdapter->getAdaptedZoom()) {
861             p->theMapAdapter->zoom_out();
862         }
863     }
864 
865     tileWidth = p->theMapAdapter->getBoundingbox().width() / p->theMapAdapter->getTilesWE(p->theMapAdapter->getZoom());
866     tileHeight = p->theMapAdapter->getBoundingbox().height() / p->theMapAdapter->getTilesNS(p->theMapAdapter->getZoom());
867     qreal w = (fRect.width() / tilesizeW) * tileWidth;
868     qreal h = (fRect.height() / tilesizeH) * tileHeight;
869 
870     if (!M_PREFS->getZoomBoris()) {
871         while (!(projVp.width() > w && -projVp.height() > h) && (p->theMapAdapter->getAdaptedZoom() < maxZoom)) {
872             p->theMapAdapter->zoom_in();
873 
874             tileWidth = p->theMapAdapter->getBoundingbox().width() / p->theMapAdapter->getTilesWE(p->theMapAdapter->getZoom());
875             tileHeight = p->theMapAdapter->getBoundingbox().height() / p->theMapAdapter->getTilesNS(p->theMapAdapter->getZoom());
876             w = (fRect.width() / tilesizeW) * tileWidth;
877             h = (fRect.height() / tilesizeH) * tileHeight;
878         }
879         if (p->theMapAdapter->getAdaptedZoom() && projVp.width() > w && -projVp.height() > h) {
880             p->theMapAdapter->zoom_out();
881             tileWidth = p->theMapAdapter->getBoundingbox().width() / p->theMapAdapter->getTilesWE(p->theMapAdapter->getZoom());
882             tileHeight = p->theMapAdapter->getBoundingbox().height() / p->theMapAdapter->getTilesNS(p->theMapAdapter->getZoom());
883             w = (fRect.width() / tilesizeW) * tileWidth;
884             h = (fRect.height() / tilesizeH) * tileHeight;
885         }
886     }
887 
888     p->AlignementTransformList.resize(maxZoom+1);
889     p->AlignementTransformList[p->theMapAdapter->getAdaptedZoom()] *= p->AlignementTransform;
890     p->AlignementTransform = QTransform();
891     QRectF alignedViewport = p->AlignementTransformList.at(p->theMapAdapter->getAdaptedZoom()).mapRect(p->Viewport);
892 
893     if (alignedViewport != p->Viewport) {
894         if (p->theProjection.getProjectionProj4() == theView.projection().getProjectionProj4() && alignedViewport == theView.viewport()) {
895             projVp.setTopLeft(theView.invertedTransform().map(fRect.topLeft()));
896             projVp.setBottomRight(theView.invertedTransform().map(fRect.bottomRight()));
897         } else
898             projVp = p->theProjection.toProjectedRectF(CoordBox(alignedViewport), rect);
899     }
900 
901     QPointF vpCenter = projVp.center();
902     QPointF upperLeft = QPointF(vpCenter.x() - w/2, vpCenter.y() + h/2);
903     QPointF lowerRight = QPointF(vpCenter.x() + w/2, vpCenter.y() - h/2);
904     QRectF vlm = QRectF(upperLeft, lowerRight);
905 
906     QPointF vp0Center = QPointF(projVp.width()/2, -projVp.height()/2);
907 
908     Coord ulCoord, lrCoord;
909     ulCoord = p->theProjection.inverse(vlm.topLeft());
910     lrCoord = p->theProjection.inverse(vlm.bottomRight());
911 
912     const QPointF tl = theView.transform().map(theView.projection().project(ulCoord));
913     const QPointF br = theView.transform().map(theView.projection().project(lrCoord));
914     QRect retRect = QRectF(tl, br).toRect();
915 
916     // Actual drawing
917     int i, j;
918     QPointF vpCenter0 = QPointF(vpCenter.x()-p->theMapAdapter->getBoundingbox().left(), p->theMapAdapter->getBoundingbox().bottom()-vpCenter.y());
919     qreal mapmiddle_tile_x = qRound(vpCenter0.x()/tileWidth);
920     qreal mapmiddle_tile_y = qRound(vpCenter0.y()/tileHeight);
921     //qDebug() << "z:" << p->theMapAdapter->getAdaptedZoom() << "; t_x:" << mapmiddle_tile_x << "; t_y:" << mapmiddle_tile_y ;
922 
923     qreal cross_x = vpCenter0.x() - mapmiddle_tile_x*tileWidth;		// position on middle tile
924     qreal cross_y = vpCenter0.y() - mapmiddle_tile_y*tileHeight;
925     //qDebug() << "cross_x:" << cross_x << "; cross_y:" << cross_y;
926 
927         // calculate how many surrounding tiles have to be drawn to fill the display
928     qreal space_left = vp0Center.x() - cross_x;
929     int tiles_left = space_left/tileWidth;
930     if (space_left>0)
931         tiles_left+=1;
932     qreal space_above = vp0Center.y() - cross_y;
933     int tiles_above = space_above/tileHeight;
934     if (space_above>0)
935         tiles_above+=1;
936 
937     qreal space_right = vp0Center.x() - (tileWidth-cross_x);
938     int tiles_right = space_right/tileWidth;
939     if (space_right>0)
940         tiles_right+=1;
941 
942     qreal space_bottom = vp0Center.y() - (tileHeight-cross_y);
943     int tiles_bottom = space_bottom/tileHeight;
944     if (space_bottom>0)
945         tiles_bottom+=1;
946 
947     QList<Tile> tiles;
948     int cross_scr_x = cross_x * tilesizeW / tileWidth;
949     int cross_scr_y = cross_y * tilesizeH / tileHeight;
950 
951     QSize pmSize = fRect.size().toSize();
952     p->newPix = QPixmap(pmSize);
953     p->newPix.fill(Qt::transparent);
954     QPainter painter(&p->newPix);
955 //    painter.drawPixmap(0, 0, tmpPm);
956 
957 //    qDebug() << "Tiles:" << tiles_right+tiles_left+1 << "x" << tiles_bottom+tiles_above+1;
958     for (i=-tiles_left; i<=tiles_right; i++)
959     {
960         for (j=-tiles_above; j<=tiles_bottom; j++)
961         {
962             if (p->theMapAdapter->isValid(mapmiddle_tile_x+i, mapmiddle_tile_y+j, p->theMapAdapter->getZoom()))
963             {
964 #ifdef Q_CC_MSVC
965                 qreal priority = _hypot(i, j);
966 #else
967                 qreal priority = hypot(i, j);
968 #endif
969                 tiles.append(Tile(i, j, priority));
970             }
971         }
972     }
973 
974     qSort(tiles);
975 
976     int n=0; // Arbitrarily limit the number of tiles to 100
977     for (QList<Tile>::const_iterator tile = tiles.begin(); tile != tiles.end() && n<100; ++tile)
978     {
979         QImage pm = p->theMapAdapter->getImageManager()->getImage(p->theMapAdapter, p->theMapAdapter->getQuery(mapmiddle_tile_x+tile->i, mapmiddle_tile_y+tile->j, p->theMapAdapter->getZoom()));
980         int x = (tile->i*tilesizeW)+pmSize.width()/2 -cross_scr_x;
981         int y = (tile->j*tilesizeH)+pmSize.height()/2-cross_scr_y;
982         if (!pm.isNull())
983             painter.drawImage(x, y, pm);
984 
985         if (M_PREFS->getDrawTileBoundary())
986             painter.drawRect(x, y, tilesizeW, tilesizeH);
987 
988         ++n;
989     }
990     painter.end();
991 
992 //    qDebug() << "tl:" << tl << "; br:" << br;
993 //    qDebug() << "vp:" << projVp;
994     //    qDebug() << "vlm:" << vlm;
995     //qDebug() << "retRect:" << retRect;
996 //    QRect expR = QRect(-retRect.left(), -retRect.top(), retRect.width()+retRect.left(), retRect.height()+retRect.top());
997 //    p->newPix.save("c:/tmp.png");
998 //    p->newPix.copy(expR).save("c:/tmp2.png");
999     return retRect;
1000 }
1001 
on_imageRequested()1002 void ImageMapLayer::on_imageRequested()
1003 {
1004     emit imageRequested(this);
1005 }
1006 
on_imageReceived()1007 void ImageMapLayer::on_imageReceived()
1008 {
1009     emit imageReceived(this);
1010 }
1011 
on_loadingFinished()1012 void ImageMapLayer::on_loadingFinished()
1013 {
1014     emit loadingFinished(this);
1015 }
1016 
toPropertiesHtml()1017 QString ImageMapLayer::toPropertiesHtml()
1018 {
1019     QString h;
1020     QRectF alignedViewport = p->AlignementTransform.mapRect(p->Viewport);
1021 
1022     h += "<u>" + name() + "</u><br/>";
1023     if (p->theMapAdapter) {
1024         if (p->theMapAdapter->getType() != IMapAdapter::DirectBackground) {
1025             h += "<i>" + tr("Server") + ": </i>" + p->theMapAdapter->getHost();
1026             h += "<br/>";
1027             if (p->theMapAdapter->isTiled()) {
1028                 h += "<i>" + tr("Tile size") + ": </i>" + QString("%1x%2").arg(p->theMapAdapter->getTileSizeW()).arg(p->theMapAdapter->getTileSizeH());
1029                 h += "<br/>";
1030                 h += "<i>" + tr("Min/Max zoom") + ": </i>" + QString("%1/%2").arg(p->theMapAdapter->getMinZoom(alignedViewport)).arg(p->theMapAdapter->getMaxZoom(alignedViewport));
1031                 h += "<br/>";
1032             }
1033         }
1034         h += "<i>" + tr("Projection") + ": </i>" + p->theMapAdapter->projection();
1035         h += "<br/>";
1036         h += p->theMapAdapter->toPropertiesHtml();
1037     }
1038     h += "";
1039 
1040     return h;
1041 }
1042 
getCurrentAlignmentTransform()1043 QTransform ImageMapLayer::getCurrentAlignmentTransform()
1044 {
1045     if (p->theMapAdapter && p->AlignementTransformList.size()) {
1046         if (p->theMapAdapter->isTiled()) {
1047             return p->AlignementTransformList.at(p->theMapAdapter->getAdaptedZoom());
1048         } else {
1049             return p->AlignementTransformList.at(0);
1050         }
1051     } else
1052         return QTransform();
1053 }
1054 
1055