Marble

PlacemarkLayer.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2006-2007 Torsten Rahn <tackat@kde.org>
4// SPDX-FileCopyrightText: 2007-2008 Inge Wallin <ingwa@kde.org>
5// SPDX-FileCopyrightText: 2011-2012 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
6//
7
8#include "PlacemarkLayer.h"
9
10#include <QPoint>
11
12#include "AbstractProjection.h"
13#include "GeoDataLatLonAltBox.h"
14#include "GeoDataStyle.h"
15#include "GeoPainter.h"
16#include "MarbleDebug.h"
17#include "RenderState.h"
18#include "ViewportParams.h"
19#include "VisiblePlacemark.h"
20#include "osm/OsmPlacemarkData.h"
21
22#define BATCH_RENDERING
23
24using namespace Marble;
25
26PlacemarkLayer::PlacemarkLayer(QAbstractItemModel *placemarkModel,
27 QItemSelectionModel *selectionModel,
28 MarbleClock *clock,
29 const StyleBuilder *styleBuilder,
30 QObject *parent)
31 : QObject(parent)
32 , m_layout(placemarkModel, selectionModel, clock, styleBuilder)
33 , m_debugModeEnabled(false)
34 , m_levelTagDebugModeEnabled(false)
35 , m_tileLevel(0)
36 , m_debugLevelTag(0)
37{
38 connect(&m_layout, SIGNAL(repaintNeeded()), SIGNAL(repaintNeeded()));
39}
40
41PlacemarkLayer::~PlacemarkLayer() = default;
42
43QStringList PlacemarkLayer::renderPosition() const
44{
45 return QStringList(QStringLiteral("PLACEMARKS"));
46}
47
48qreal PlacemarkLayer::zValue() const
49{
50 return 2.0;
51}
52
53bool PlacemarkLayer::render(GeoPainter *geoPainter, ViewportParams *viewport, const QString &renderPos, GeoSceneLayer *layer)
54{
55 Q_UNUSED(renderPos)
56 Q_UNUSED(layer)
57
58 QList<VisiblePlacemark *> visiblePlacemarks = m_layout.generateLayout(viewport, m_tileLevel);
59 // draw placemarks less important first
60 QList<VisiblePlacemark *>::const_iterator visit = visiblePlacemarks.constEnd();
61 QList<VisiblePlacemark *>::const_iterator itEnd = visiblePlacemarks.constBegin();
62
63 QPainter *const painter = geoPainter;
64
65 bool const repeatableX = viewport->currentProjection()->repeatableX();
66 int const radius4 = 4 * viewport->radius();
67
68#ifdef BATCH_RENDERING
70#endif
71
72 while (visit != itEnd) {
73 --visit;
74
75 VisiblePlacemark *const mark = *visit;
76 if (m_levelTagDebugModeEnabled) {
77 if (mark->placemark()->hasOsmData()) {
78 QHash<QString, QString>::const_iterator tagIter = mark->placemark()->osmData().findTag(QStringLiteral("level"));
79 if (tagIter != mark->placemark()->osmData().tagsEnd()) {
80 const int val = tagIter.value().toInt();
81 if (val != m_debugLevelTag) {
82 continue;
83 }
84 }
85 }
86 }
87
88 // Intentionally converting positions from floating point to pixel aligned screen grid below
89 QRect labelRect(mark->labelRect().toRect());
90 QPoint symbolPos(mark->symbolPosition().toPoint());
91
92 // when the map is such zoomed out that a given place
93 // appears many times, we draw one placemark at each
94 if (repeatableX) {
95 const int symbolX = symbolPos.x();
96 const int textX = labelRect.x();
97
98 for (int i = symbolX % radius4, width = viewport->width(); i <= width; i += radius4) {
99 labelRect.moveLeft(i - symbolX + textX);
100 symbolPos.setX(i);
101
102 if (!mark->symbolPixmap().isNull()) {
103#ifdef BATCH_RENDERING
104 QRect symbolRect = mark->symbolPixmap().rect();
105 QPainter::PixmapFragment pixmapFragment = QPainter::PixmapFragment::create(QPointF(symbolPos + symbolRect.center()), QRectF(symbolRect));
106
107 auto iter = hash.find(mark->symbolId());
108 if (iter == hash.end()) {
109 Fragment fragment;
110 fragment.pixmap = mark->symbolPixmap();
111 fragment.fragments << pixmapFragment;
112 hash.insert(mark->symbolId(), fragment);
113 } else {
114 auto &fragment = iter.value();
115 fragment.fragments << pixmapFragment;
116 }
117#else
118 painter->drawPixmap(symbolPos, mark->symbolPixmap());
119#endif
120 }
121 if (!mark->labelPixmap().isNull()) {
122 painter->drawPixmap(labelRect, mark->labelPixmap());
123 }
124 }
125 } else { // simple case, one draw per placemark
126
127 if (!mark->symbolPixmap().isNull()) {
128#ifdef BATCH_RENDERING
129 QRect symbolRect = mark->symbolPixmap().rect();
130 QPainter::PixmapFragment pixmapFragment = QPainter::PixmapFragment::create(QPointF(symbolPos + symbolRect.center()), QRectF(symbolRect));
131
132 auto iter = hash.find(mark->symbolId());
133 if (iter == hash.end()) {
134 Fragment fragment;
135 fragment.pixmap = mark->symbolPixmap();
136 fragment.fragments << pixmapFragment;
137 hash.insert(mark->symbolId(), fragment);
138 } else {
139 auto &fragment = iter.value();
140 fragment.fragments << pixmapFragment;
141 }
142#else
143 painter->drawPixmap(symbolPos, mark->symbolPixmap());
144#endif
145 }
146 if (!mark->labelPixmap().isNull()) {
147 painter->drawPixmap(labelRect, mark->labelPixmap());
148 }
149 }
150 }
151
152#ifdef BATCH_RENDERING
153 for (auto iter = hash.begin(), end = hash.end(); iter != end; ++iter) {
154 auto const &fragment = iter.value();
155 if (m_debugModeEnabled) {
156 QPixmap debugPixmap(fragment.pixmap.size());
157 QColor backgroundColor;
158 QString idStr = iter.key().section(QLatin1Char('/'), -1);
159 if (idStr.length() > 2) {
160 idStr.remove(QStringLiteral("shop_"));
161 backgroundColor =
162 QColor((10 * (int)(idStr[0].toLatin1())) % 255, (10 * (int)(idStr[1].toLatin1())) % 255, (10 * (int)(idStr[2].toLatin1())) % 255);
163 } else {
164 backgroundColor = QColor((quint64)(&iter.key()));
165 }
166 debugPixmap.fill(backgroundColor);
167 QPainter pixpainter;
168 pixpainter.begin(&debugPixmap);
169 pixpainter.drawPixmap(0, 0, fragment.pixmap);
170 pixpainter.end();
171 iter.value().pixmap = debugPixmap;
172 }
173 painter->drawPixmapFragments(fragment.fragments.data(), fragment.fragments.size(), fragment.pixmap);
174 }
175#endif
176
177 if (m_debugModeEnabled) {
178 renderDebug(geoPainter, viewport, visiblePlacemarks);
179 }
180
181 return true;
182}
183
184RenderState PlacemarkLayer::renderState() const
185{
186 return RenderState(QStringLiteral("Placemarks"));
187}
188
189QString PlacemarkLayer::runtimeTrace() const
190{
191 return m_layout.runtimeTrace();
192}
193
194QList<const GeoDataFeature *> PlacemarkLayer::whichPlacemarkAt(const QPoint &pos)
195{
196 return m_layout.whichPlacemarkAt(pos);
197}
198
199bool PlacemarkLayer::hasPlacemarkAt(const QPoint &pos)
200{
201 return m_layout.hasPlacemarkAt(pos);
202}
203
204bool PlacemarkLayer::isDebugModeEnabled() const
205{
206 return m_debugModeEnabled;
207}
208
209void PlacemarkLayer::setDebugModeEnabled(bool enabled)
210{
211 m_debugModeEnabled = enabled;
212}
213
214void PlacemarkLayer::setShowPlaces(bool show)
215{
216 m_layout.setShowPlaces(show);
217}
218
219void PlacemarkLayer::setShowCities(bool show)
220{
221 m_layout.setShowCities(show);
222}
223
224void PlacemarkLayer::setShowTerrain(bool show)
225{
226 m_layout.setShowTerrain(show);
227}
228
229void PlacemarkLayer::setShowOtherPlaces(bool show)
230{
231 m_layout.setShowOtherPlaces(show);
232}
233
234void PlacemarkLayer::setShowLandingSites(bool show)
235{
236 m_layout.setShowLandingSites(show);
237}
238
239void PlacemarkLayer::setShowCraters(bool show)
240{
241 m_layout.setShowCraters(show);
242}
243
244void PlacemarkLayer::setShowMaria(bool show)
245{
246 m_layout.setShowMaria(show);
247}
248
249void PlacemarkLayer::requestStyleReset()
250{
251 m_layout.requestStyleReset();
252}
253
254void PlacemarkLayer::setTileLevel(int tileLevel)
255{
256 m_tileLevel = tileLevel;
257}
258
259void PlacemarkLayer::renderDebug(GeoPainter *painter, ViewportParams *viewport, const QList<VisiblePlacemark *> &placemarks) const
260{
261 painter->save();
262 painter->setFont(QFont(QStringLiteral("Sans Serif"), 7));
263 painter->setBrush(QBrush(Qt::NoBrush));
264 auto const latLonAltBox = viewport->viewLatLonAltBox();
265
266 using Placemarks = QSet<VisiblePlacemark *>;
267 const auto visiblePlacemarks = m_layout.visiblePlacemarks();
268 Placemarks const hidden =
269 Placemarks(visiblePlacemarks.constBegin(), visiblePlacemarks.constEnd()).subtract(Placemarks(placemarks.constBegin(), placemarks.constEnd()));
270
271 for (auto placemark : hidden) {
272 bool const inside = latLonAltBox.contains(placemark->coordinates());
273 painter->setPen(QPen(QColor(inside ? Qt::red : Qt::darkYellow)));
274 painter->drawRect(placemark->boundingBox());
275 }
276
277 painter->setPen(QPen(QColor(Qt::blue)));
278 for (auto placemark : placemarks) {
279 painter->drawRect(placemark->boundingBox());
280 }
281
282 painter->setPen(QPen(QColor(Qt::green)));
283 for (auto placemark : placemarks) {
284 painter->drawRect(placemark->labelRect());
285 painter->drawRect(placemark->symbolRect());
286 }
287
288 auto const height = painter->fontMetrics().height();
289 painter->setPen(QPen(QColor(Qt::black)));
290 for (auto placemark : placemarks) {
291 QPoint position = placemark->symbolRect().bottomLeft().toPoint() + QPoint(0, qRound(0.8 * height));
292 auto const popularity = placemark->placemark()->popularity();
293 painter->drawText(position, QStringLiteral("p: %1").arg(popularity));
294 position -= QPoint(0, placemark->symbolRect().height() + height);
295 auto const zoomLevel = placemark->placemark()->zoomLevel();
296 painter->drawText(position, QStringLiteral("z: %1").arg(zoomLevel));
297 }
298
299 painter->restore();
300}
301
302void PlacemarkLayer::setLevelTagDebugModeEnabled(bool enabled)
303{
304 if (m_levelTagDebugModeEnabled != enabled) {
305 m_levelTagDebugModeEnabled = enabled;
306 Q_EMIT repaintNeeded();
307 }
308}
309
310bool PlacemarkLayer::levelTagDebugModeEnabled() const
311{
312 return m_levelTagDebugModeEnabled;
313}
314
315void PlacemarkLayer::setDebugLevelTag(int level)
316{
317 if (m_debugLevelTag != level) {
318 m_debugLevelTag = level;
319 Q_EMIT repaintNeeded();
320 }
321}
322
323#include "moc_PlacemarkLayer.cpp"
This file contains the headers for AbstractProjection.
This file contains the headers for ViewportParams.
virtual bool repeatableX() const
Returns whether the projection allows for wrapping in x direction (along the longitude scale).
OsmPlacemarkData & osmData()
Quick, safe accessor to the placemark's OsmPlacemarkData stored within it's ExtendedData.
A painter that allows to draw geometric primitives on the map.
Definition GeoPainter.h:86
void drawText(const GeoDataCoordinates &position, const QString &text, qreal xOffset=0.0, qreal yOffset=0.0, qreal width=0.0, qreal height=0.0, const QTextOption &option=QTextOption())
Draws the given text at a given geographic position. The text is drawn starting at the given position...
void drawRect(const GeoDataCoordinates &centerPosition, qreal width, qreal height, bool isGeoProjected=false)
Draws a rectangle at the given position. The rectangle is placed with its center located at the given...
Layer of a GeoScene document.
QHash< QString, QString >::const_iterator findTag(const QString &key) const
tagValue returns a pointer to the tag that has key as key or the end iterator if there is no such tag
QList< const GeoDataFeature * > whichPlacemarkAt(const QPoint &pos)
Returns a list of model indexes that are at position pos.
QList< VisiblePlacemark * > generateLayout(const ViewportParams *viewport, int tileLevel)
A public class that controls what is visible in the viewport of a Marble map.
A class which represents the visible place marks on a map.
const QPointF & symbolPosition() const
Returns the position of the place mark symbol on the map.
const QPixmap & labelPixmap()
Returns the pixmap of the place mark name label.
const QString & symbolId() const
Returns the id for the place mark symbol.
const GeoDataPlacemark * placemark() const
Returns the index of the place mark model which is associated with this visible place mark.
const QPixmap & symbolPixmap() const
Returns the pixmap of the place mark symbol.
const QRectF & labelRect() const
Returns the area covered by the place mark name label on the map.
QStringView level(QStringView ifopt)
Binds a QML item to a specific geodetic location in screen coordinates.
int height() const const
iterator begin()
iterator end()
iterator find(const Key &key)
iterator insert(const Key &key, const T &value)
const_iterator constBegin() const const
const_iterator constEnd() const const
Q_EMITQ_EMIT
PixmapFragment create(const QPointF &pos, const QRectF &sourceRect, qreal scaleX, qreal scaleY, qreal rotation, qreal opacity)
bool begin(QPaintDevice *device)
void drawPixmap(const QPoint &point, const QPixmap &pixmap)
void drawPixmapFragments(const PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, PixmapFragmentHints hints)
bool end()
QFontMetrics fontMetrics() const const
void restore()
void save()
void setFont(const QFont &font)
bool isNull() const const
QRect rect() const const
QSize size() const const
QPoint toPoint() const const
QPoint center() const const
QRect toRect() const const
QString & fill(QChar ch, qsizetype size)
qsizetype length() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString section(QChar sep, qsizetype start, qsizetype end, SectionFlags flags) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
qsizetype size() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 8 2024 12:02:44 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.