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