File indexing completed on 2025-01-05 03:59:18

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