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