File indexing completed on 2024-05-05 03:49:49

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2006-2007 Torsten Rahn <tackat@kde.org>
0004 // SPDX-FileCopyrightText: 2007-2008 Inge Wallin <ingwa@kde.org>
0005 // SPDX-FileCopyrightText: 2011-2012 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
0006 //
0007 
0008 #include "PlacemarkLayer.h"
0009 
0010 #include <QPoint>
0011 
0012 #include "MarbleDebug.h"
0013 #include "AbstractProjection.h"
0014 #include "GeoDataStyle.h"
0015 #include "GeoPainter.h"
0016 #include "GeoDataLatLonAltBox.h"
0017 #include "ViewportParams.h"
0018 #include "VisiblePlacemark.h"
0019 #include "RenderState.h"
0020 #include "osm/OsmPlacemarkData.h"
0021 
0022 #define BATCH_RENDERING
0023 
0024 using namespace Marble;
0025 
0026 PlacemarkLayer::PlacemarkLayer(QAbstractItemModel *placemarkModel,
0027                                 QItemSelectionModel *selectionModel,
0028                                 MarbleClock *clock, const StyleBuilder *styleBuilder,
0029                                 QObject *parent ) :
0030     QObject( parent ),
0031     m_layout( placemarkModel, selectionModel, clock, styleBuilder ),
0032     m_debugModeEnabled(false),
0033     m_levelTagDebugModeEnabled(false),
0034     m_tileLevel(0),
0035     m_debugLevelTag(0)
0036 {
0037     connect( &m_layout, SIGNAL(repaintNeeded()), SIGNAL(repaintNeeded()) );
0038 }
0039 
0040 PlacemarkLayer::~PlacemarkLayer()
0041 {
0042 }
0043 
0044 QStringList PlacemarkLayer::renderPosition() const
0045 {
0046     return QStringList(QStringLiteral("PLACEMARKS"));
0047 }
0048 
0049 qreal PlacemarkLayer::zValue() const
0050 {
0051     return 2.0;
0052 }
0053 
0054 bool PlacemarkLayer::render( GeoPainter *geoPainter, ViewportParams *viewport,
0055                                const QString &renderPos, GeoSceneLayer *layer )
0056 {
0057     Q_UNUSED( renderPos )
0058     Q_UNUSED( layer )
0059 
0060     QVector<VisiblePlacemark*> visiblePlacemarks = m_layout.generateLayout( viewport, m_tileLevel );
0061     // draw placemarks less important first
0062     QVector<VisiblePlacemark*>::const_iterator visit = visiblePlacemarks.constEnd();
0063     QVector<VisiblePlacemark*>::const_iterator itEnd = visiblePlacemarks.constBegin();
0064 
0065     QPainter *const painter = geoPainter;
0066 
0067     bool const repeatableX = viewport->currentProjection()->repeatableX();
0068     int const radius4 = 4 * viewport->radius();
0069 
0070 #ifdef BATCH_RENDERING
0071     QHash <QString, Fragment> hash;
0072 #endif
0073 
0074     while ( visit != itEnd ) {
0075         --visit;
0076 
0077         VisiblePlacemark *const mark = *visit;
0078         if (m_levelTagDebugModeEnabled) {
0079             if (mark->placemark()->hasOsmData()) {
0080                 QHash<QString, QString>::const_iterator tagIter = mark->placemark()->osmData().findTag(QStringLiteral("level"));
0081                 if (tagIter != mark->placemark()->osmData().tagsEnd()) {
0082                     const int val = tagIter.value().toInt();
0083                     if (val != m_debugLevelTag) {
0084                         continue;
0085                     }
0086                 }
0087             }
0088         }
0089 
0090         // Intentionally converting positions from floating point to pixel aligned screen grid below
0091         QRect labelRect( mark->labelRect().toRect() );
0092         QPoint symbolPos( mark->symbolPosition().toPoint());
0093 
0094         // when the map is such zoomed out that a given place
0095         // appears many times, we draw one placemark at each
0096         if (repeatableX) {
0097             const int symbolX = symbolPos.x();
0098             const int textX =   labelRect.x();
0099 
0100             for (int i = symbolX % radius4, width = viewport->width(); i <= width; i += radius4) {
0101                 labelRect.moveLeft(i - symbolX + textX);
0102                 symbolPos.setX(i);
0103 
0104                 if (!mark->symbolPixmap().isNull()) {
0105 #ifdef BATCH_RENDERING
0106                     QRect symbolRect = mark->symbolPixmap().rect();
0107                     QPainter::PixmapFragment pixmapFragment = QPainter::PixmapFragment::create(QPointF(symbolPos+symbolRect.center()),QRectF(symbolRect));
0108 
0109                     auto iter = hash.find(mark->symbolId());
0110                     if (iter == hash.end()) {
0111                         Fragment fragment;
0112                         fragment.pixmap = mark->symbolPixmap();
0113                         fragment.fragments << pixmapFragment;
0114                         hash.insert(mark->symbolId(), fragment);
0115                     } else {
0116                         auto & fragment = iter.value();
0117                         fragment.fragments << pixmapFragment;
0118                     }
0119 #else
0120                     painter->drawPixmap( symbolPos, mark->symbolPixmap() );
0121 #endif
0122                 }
0123                 if (!mark->labelPixmap().isNull()) {
0124                     painter->drawPixmap( labelRect, mark->labelPixmap() );
0125                 }
0126             }
0127         } else { // simple case, one draw per placemark
0128 
0129             if (!mark->symbolPixmap().isNull()) {
0130 #ifdef BATCH_RENDERING
0131                 QRect symbolRect = mark->symbolPixmap().rect();
0132                 QPainter::PixmapFragment pixmapFragment = QPainter::PixmapFragment::create(QPointF(symbolPos+symbolRect.center()),QRectF(symbolRect));
0133 
0134                 auto iter = hash.find(mark->symbolId());
0135                 if (iter == hash.end()) {
0136                     Fragment fragment;
0137                     fragment.pixmap = mark->symbolPixmap();
0138                     fragment.fragments << pixmapFragment;
0139                     hash.insert(mark->symbolId(), fragment);
0140                 }
0141                 else {
0142                     auto & fragment = iter.value();
0143                     fragment.fragments << pixmapFragment;
0144                 }
0145 #else
0146                 painter->drawPixmap( symbolPos, mark->symbolPixmap() );
0147 #endif
0148             }
0149             if (!mark->labelPixmap().isNull()) {
0150                 painter->drawPixmap( labelRect, mark->labelPixmap() );
0151             }
0152         }
0153     }
0154 
0155 #ifdef BATCH_RENDERING
0156     for (auto iter = hash.begin(), end = hash.end(); iter != end; ++iter) {
0157         auto const & fragment = iter.value();
0158         if (m_debugModeEnabled) {
0159             QPixmap debugPixmap(fragment.pixmap.size());
0160             QColor backgroundColor;
0161             QString idStr = iter.key().section('/', -1);
0162             if (idStr.length() > 2) {
0163               idStr.remove("shop_");
0164               backgroundColor = QColor(
0165                           (10 * (int)(idStr[0].toLatin1()))%255,
0166                           (10 * (int)(idStr[1].toLatin1()))%255,
0167                           (10 * (int)(idStr[2].toLatin1()))%255 );
0168             }
0169             else {
0170               backgroundColor = QColor((quint64)(&iter.key()));
0171             }
0172             debugPixmap.fill(backgroundColor);
0173             QPainter pixpainter;
0174             pixpainter.begin(&debugPixmap);
0175             pixpainter.drawPixmap(0, 0, fragment.pixmap);
0176             pixpainter.end();
0177             iter.value().pixmap = debugPixmap;
0178         }
0179         painter->drawPixmapFragments(fragment.fragments.data(), fragment.fragments.size(), fragment.pixmap);
0180     }
0181 #endif
0182 
0183     if (m_debugModeEnabled) {
0184         renderDebug(geoPainter, viewport, visiblePlacemarks);
0185     }
0186 
0187     return true;
0188 }
0189 
0190 RenderState PlacemarkLayer::renderState() const
0191 {
0192     return RenderState(QStringLiteral("Placemarks"));
0193 }
0194 
0195 QString PlacemarkLayer::runtimeTrace() const
0196 {
0197     return m_layout.runtimeTrace();
0198 }
0199 
0200 QVector<const GeoDataFeature *> PlacemarkLayer::whichPlacemarkAt( const QPoint &pos )
0201 {
0202     return m_layout.whichPlacemarkAt( pos );
0203 }
0204 
0205 bool PlacemarkLayer::hasPlacemarkAt(const QPoint &pos)
0206 {
0207     return m_layout.hasPlacemarkAt(pos);
0208 }
0209 
0210 bool PlacemarkLayer::isDebugModeEnabled() const
0211 {
0212     return m_debugModeEnabled;
0213 }
0214 
0215 void PlacemarkLayer::setDebugModeEnabled(bool enabled)
0216 {
0217     m_debugModeEnabled = enabled;
0218 }
0219 
0220 void PlacemarkLayer::setShowPlaces( bool show )
0221 {
0222     m_layout.setShowPlaces( show );
0223 }
0224 
0225 void PlacemarkLayer::setShowCities( bool show )
0226 {
0227     m_layout.setShowCities( show );
0228 }
0229 
0230 void PlacemarkLayer::setShowTerrain( bool show )
0231 {
0232     m_layout.setShowTerrain( show );
0233 }
0234 
0235 void PlacemarkLayer::setShowOtherPlaces( bool show )
0236 {
0237     m_layout.setShowOtherPlaces( show );
0238 }
0239 
0240 void PlacemarkLayer::setShowLandingSites( bool show )
0241 {
0242     m_layout.setShowLandingSites( show );
0243 }
0244 
0245 void PlacemarkLayer::setShowCraters( bool show )
0246 {
0247     m_layout.setShowCraters( show );
0248 }
0249 
0250 void PlacemarkLayer::setShowMaria( bool show )
0251 {
0252     m_layout.setShowMaria( show );
0253 }
0254 
0255 void PlacemarkLayer::requestStyleReset()
0256 {
0257     m_layout.requestStyleReset();
0258 }
0259 
0260 void PlacemarkLayer::setTileLevel(int tileLevel)
0261 {
0262     m_tileLevel = tileLevel;
0263 }
0264 
0265 void PlacemarkLayer::renderDebug(GeoPainter *painter, ViewportParams *viewport, const QVector<VisiblePlacemark *> &placemarks) const
0266 {
0267     painter->save();
0268     painter->setFont(QFont(QStringLiteral("Sans Serif"), 7));
0269     painter->setBrush(QBrush(Qt::NoBrush));
0270     auto const latLonAltBox = viewport->viewLatLonAltBox();
0271 
0272     using Placemarks = QSet<VisiblePlacemark *>;
0273     const auto visiblePlacemarks = m_layout.visiblePlacemarks();
0274     Placemarks const hidden = Placemarks(visiblePlacemarks.constBegin(), visiblePlacemarks.constEnd())
0275         .subtract(Placemarks(placemarks.constBegin(), placemarks.constEnd()));
0276 
0277     for (auto placemark: hidden) {
0278         bool const inside = latLonAltBox.contains(placemark->coordinates());
0279         painter->setPen(QPen(QColor(inside ? Qt::red : Qt::darkYellow)));
0280         painter->drawRect(placemark->boundingBox());
0281     }
0282 
0283     painter->setPen(QPen(QColor(Qt::blue)));
0284     for (auto placemark: placemarks) {
0285         painter->drawRect(placemark->boundingBox());
0286     }
0287 
0288     painter->setPen(QPen(QColor(Qt::green)));
0289     for (auto placemark: placemarks) {
0290         painter->drawRect(placemark->labelRect());
0291         painter->drawRect(placemark->symbolRect());
0292     }
0293 
0294     auto const height = painter->fontMetrics().height();
0295     painter->setPen(QPen(QColor(Qt::black)));
0296     for (auto placemark: placemarks) {
0297         QPoint position = placemark->symbolRect().bottomLeft().toPoint() + QPoint(0, qRound(0.8 * height));
0298         auto const popularity = placemark->placemark()->popularity();
0299         painter->drawText(position, QStringLiteral("p: %1").arg(popularity));
0300         position -= QPoint(0, placemark->symbolRect().height() + height);
0301         auto const zoomLevel = placemark->placemark()->zoomLevel();
0302         painter->drawText(position, QStringLiteral("z: %1").arg(zoomLevel));
0303     }
0304 
0305     painter->restore();
0306 }
0307 
0308 void PlacemarkLayer::setLevelTagDebugModeEnabled(bool enabled)
0309 {
0310     if (m_levelTagDebugModeEnabled != enabled) {
0311         m_levelTagDebugModeEnabled = enabled;
0312         emit repaintNeeded();
0313     }
0314 }
0315 
0316 bool PlacemarkLayer::levelTagDebugModeEnabled() const
0317 {
0318     return m_levelTagDebugModeEnabled;
0319 }
0320 
0321 void PlacemarkLayer::setDebugLevelTag(int level)
0322 {
0323     if (m_debugLevelTag != level) {
0324         m_debugLevelTag = level;
0325         emit repaintNeeded();
0326     }
0327 }
0328 
0329 #include "moc_PlacemarkLayer.cpp"
0330