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