Commit 09ecae21 authored by Dennis Nienhüser's avatar Dennis Nienhüser
Browse files

Improve visible placemark caching. Lazy label pixmap creation.

Deleted placemarks (e.g. tile removed in vector osm) were kept in
the cache forever with their visible placemark counterpart only being
deleted on a style change (~map theme change). Placemarks that moved
out of the viewport but not being deleted directly however had their
visible placemark counterpart deleted directly, leading to a costly
recreation when the placemark moved back into the viewport soon after.

Now visible placemarks are cached only in an area around the viewport,
and eventually cleaned up when their placemark counterpart is deleted.

Lazy label pixmap creation is useful since some placemarks will never
have their label shown, its creation however is rather costly due to
the painter path involved (with glow style).
parent 63dc1432
......@@ -361,6 +361,7 @@ QVector<VisiblePlacemark *> PlacemarkLayout::generateLayout( const ViewportParam
// First handle the selected placemarks as they have the highest priority.
const QModelIndexList selectedIndexes = m_selectionModel->selection().indexes();
auto const viewLatLonAltBox = viewport->viewLatLonAltBox();
for ( int i = 0; i < selectedIndexes.count(); ++i ) {
const QModelIndex index = selectedIndexes.at( i );
......@@ -374,14 +375,13 @@ QVector<VisiblePlacemark *> PlacemarkLayout::generateLayout( const ViewportParam
qreal x = 0;
qreal y = 0;
if ( !viewport->viewLatLonAltBox().contains( coordinates ) ||
if ( !viewLatLonAltBox.contains( coordinates ) ||
! viewport->screenCoordinates( coordinates, x, y ))
{
delete m_visiblePlacemarks.take( placemark );
continue;
}
if( layoutPlacemark( placemark, x, y, true) ) {
if( layoutPlacemark( placemark, coordinates, x, y, true) ) {
// Make sure not to draw more placemarks on the screen than
// specified by placemarksOnScreenLimit().
if ( placemarksOnScreenLimit( viewport->size() ) )
......@@ -400,7 +400,6 @@ QVector<VisiblePlacemark *> PlacemarkLayout::generateLayout( const ViewportParam
}
qSort(placemarkList.begin(), placemarkList.end(), GeoDataPlacemark::placemarkLayoutOrderCompare);
auto const viewLatLonAltBox = viewport->viewLatLonAltBox();
foreach ( const GeoDataPlacemark *placemark, placemarkList ) {
const GeoDataCoordinates coordinates = placemarkIconCoordinates( placemark );
if ( !coordinates.isValid() ) {
......@@ -417,7 +416,6 @@ QVector<VisiblePlacemark *> PlacemarkLayout::generateLayout( const ViewportParam
if ( !viewLatLonAltBox.contains( coordinates ) ||
! viewport->screenCoordinates( coordinates, x, y )) {
delete m_visiblePlacemarks.take( placemark );
continue;
}
......@@ -471,7 +469,7 @@ QVector<VisiblePlacemark *> PlacemarkLayout::generateLayout( const ViewportParam
// we check for the selected state after all other filters
bool isSelected = false;
foreach ( const QModelIndex &index, selection.indexes() ) {
const GeoDataPlacemark *mark = dynamic_cast<GeoDataPlacemark*>(qvariant_cast<GeoDataObject*>(index.data( MarblePlacemarkModel::ObjectPointerRole ) ));
const GeoDataPlacemark *mark = static_cast<GeoDataPlacemark*>(qvariant_cast<GeoDataObject*>(index.data( MarblePlacemarkModel::ObjectPointerRole ) ));
if (mark == placemark ) {
isSelected = true;
break;
......@@ -480,7 +478,7 @@ QVector<VisiblePlacemark *> PlacemarkLayout::generateLayout( const ViewportParam
if ( isSelected )
continue;
if( layoutPlacemark( placemark, x, y, isSelected ) ) {
if( layoutPlacemark( placemark, coordinates, x, y, isSelected ) ) {
// Make sure not to draw more placemarks on the screen than
// specified by placemarksOnScreenLimit().
if ( placemarksOnScreenLimit( viewport->size() ) )
......@@ -488,6 +486,19 @@ QVector<VisiblePlacemark *> PlacemarkLayout::generateLayout( const ViewportParam
}
}
if (m_visiblePlacemarks.size() > qMax(100, 4 * m_paintOrder.size())) {
auto const extendedBox = viewLatLonAltBox.scaled(2.0, 2.0);
QVector<VisiblePlacemark*> outdated;
for (auto placemark: m_visiblePlacemarks) {
if (!extendedBox.contains(placemark->coordinates())) {
outdated << placemark;
}
}
for (auto placemark: outdated) {
delete m_visiblePlacemarks.take(placemark->placemark());
}
}
m_runtimeTrace = QStringLiteral("Placemarks: %1 Drawn: %2").arg(placemarkList.count()).arg(m_paintOrder.size());
return m_paintOrder;
}
......@@ -502,7 +513,7 @@ QList<VisiblePlacemark *> PlacemarkLayout::visiblePlacemarks() const
return m_visiblePlacemarks.values();
}
bool PlacemarkLayout::layoutPlacemark( const GeoDataPlacemark *placemark, qreal x, qreal y, bool selected )
bool PlacemarkLayout::layoutPlacemark( const GeoDataPlacemark *placemark, const GeoDataCoordinates &coordinates, qreal x, qreal y, bool selected )
{
// Find the corresponding visible placemark
VisiblePlacemark *mark = m_visiblePlacemarks.value( placemark );
......@@ -513,7 +524,7 @@ bool PlacemarkLayout::layoutPlacemark( const GeoDataPlacemark *placemark, qreal
// @todo: Set / adjust to tile level
parameters.placemark = placemark;
mark = new VisiblePlacemark(placemark, m_styleBuilder->createStyle(parameters));
mark = new VisiblePlacemark(placemark, coordinates, m_styleBuilder->createStyle(parameters));
m_visiblePlacemarks.insert( placemark, mark );
connect( mark, SIGNAL(updateNeeded()), this, SIGNAL(repaintNeeded()) );
}
......
......@@ -116,7 +116,7 @@ class PlacemarkLayout : public QObject
void styleReset();
static QSet<TileId> visibleTiles( const ViewportParams *viewport );
bool layoutPlacemark( const GeoDataPlacemark *placemark, qreal x, qreal y, bool selected );
bool layoutPlacemark(const GeoDataPlacemark *placemark, const GeoDataCoordinates &coordinates, qreal x, qreal y, bool selected );
/**
* Returns the coordinates at which an icon should be drawn for the @p placemark.
......
......@@ -26,16 +26,17 @@
using namespace Marble;
VisiblePlacemark::VisiblePlacemark( const GeoDataPlacemark *placemark, const GeoDataStyle::ConstPtr &style )
VisiblePlacemark::VisiblePlacemark( const GeoDataPlacemark *placemark, const GeoDataCoordinates &coordinates, const GeoDataStyle::ConstPtr &style )
: m_placemark( placemark ),
m_selected( false ),
m_style(style)
m_labelDirty(true),
m_style(style),
m_coordinates(coordinates)
{
const RemoteIconLoader *remoteLoader = style->iconStyle().remoteIconLoader();
QObject::connect( remoteLoader, SIGNAL(iconReady()),
this, SLOT(setSymbolPixmap()) );
drawLabelPixmap();
setSymbolPixmap();
}
......@@ -58,7 +59,7 @@ void VisiblePlacemark::setSelected( bool selected )
{
if (selected != m_selected) {
m_selected = selected;
drawLabelPixmap();
m_labelDirty = true;
}
}
......@@ -107,8 +108,12 @@ void VisiblePlacemark::setSymbolPosition( const QPointF& position )
m_symbolPosition = position;
}
const QPixmap& VisiblePlacemark::labelPixmap() const
const QPixmap& VisiblePlacemark::labelPixmap()
{
if (m_labelDirty) {
drawLabelPixmap();
}
return m_labelPixmap;
}
......@@ -136,7 +141,7 @@ void VisiblePlacemark::setLabelRect( const QRectF& labelRect )
void VisiblePlacemark::setStyle(const GeoDataStyle::ConstPtr &style)
{
m_style = style;
drawLabelPixmap();
m_labelDirty = true;
setSymbolPixmap();
}
......@@ -155,8 +160,14 @@ QRectF VisiblePlacemark::boundingBox() const
return m_labelRect.isEmpty() ? symbolRect() : m_labelRect.united(symbolRect());
}
const GeoDataCoordinates &VisiblePlacemark::coordinates() const
{
return m_coordinates;
}
void VisiblePlacemark::drawLabelPixmap()
{
m_labelDirty = false;
QString labelName = m_placemark->displayName();
if ( labelName.isEmpty() || m_style->labelStyle().color() == QColor(Qt::transparent) ) {
m_labelPixmap = QPixmap();
......
......@@ -22,6 +22,7 @@
#include <QRectF>
#include <GeoDataStyle.h>
#include <GeoDataCoordinates.h>
namespace Marble
{
......@@ -41,7 +42,7 @@ class VisiblePlacemark : public QObject
Q_OBJECT
public:
explicit VisiblePlacemark(const GeoDataPlacemark *placemark, const GeoDataStyle::ConstPtr &style);
explicit VisiblePlacemark(const GeoDataPlacemark *placemark, const GeoDataCoordinates &coordinates, const GeoDataStyle::ConstPtr &style);
/**
* Returns the index of the place mark model which
......@@ -82,7 +83,7 @@ class VisiblePlacemark : public QObject
/**
* Returns the pixmap of the place mark name label.
*/
const QPixmap& labelPixmap() const;
const QPixmap& labelPixmap();
/**
* Returns the area covered by the place mark name label on the map.
......@@ -108,6 +109,8 @@ class VisiblePlacemark : public QObject
QRectF boundingBox() const;
const GeoDataCoordinates & coordinates() const;
Q_SIGNALS:
void updateNeeded();
......@@ -124,10 +127,12 @@ private Q_SLOTS:
QPointF m_symbolPosition; // position of the placemark's symbol
bool m_selected; // state of the placemark
QPixmap m_labelPixmap; // the text label (most often name)
bool m_labelDirty;
QRectF m_labelRect; // bounding box of label
mutable QPixmap m_symbolPixmap; // cached value
GeoDataStyle::ConstPtr m_style;
GeoDataCoordinates m_coordinates;
};
}
......
......@@ -20,6 +20,7 @@
#include "GeoDataStyle.h"
#include "GeoPainter.h"
#include "GeoDataPlacemark.h"
#include "GeoDataLatLonAltBox.h"
#include "ViewportParams.h"
#include "VisiblePlacemark.h"
#include "RenderState.h"
......@@ -210,15 +211,16 @@ bool PlacemarkLayer::testXBug()
void PlacemarkLayer::renderDebug(GeoPainter *painter, ViewportParams *viewport, const QVector<VisiblePlacemark *> &placemarks)
{
Q_UNUSED(viewport);
painter->save();
painter->setBrush(QBrush(Qt::NoBrush));
auto const latLonAltBox = viewport->viewLatLonAltBox();
typedef QSet<VisiblePlacemark*> Placemarks;
Placemarks const hidden = Placemarks::fromList(m_layout.visiblePlacemarks()).subtract(Placemarks::fromList(placemarks.toList()));
painter->setPen(QPen(QColor(Qt::red)));
for (auto placemark: hidden) {
bool const inside = latLonAltBox.contains(placemark->coordinates());
painter->setPen(QPen(QColor(inside ? Qt::red : Qt::darkYellow)));
painter->drawRect(placemark->boundingBox());
}
......@@ -235,7 +237,6 @@ void PlacemarkLayer::renderDebug(GeoPainter *painter, ViewportParams *viewport,
painter->drawText(placemark->symbolRect().bottomLeft(), popularity);
}
painter->restore();
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment