summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Nienhüser <nienhueser@kde.org>2016-11-06 09:46:34 (GMT)
committerDennis Nienhüser <nienhueser@kde.org>2016-11-06 09:46:34 (GMT)
commit8955569d0b65bd63bc367c31a8f5d97b2f0a8471 (patch)
treefa782117e920bf841728b004fa4704ac88a536c6
parent7de7cf170957ee9836f8361d66b64e00c15e24f1 (diff)
Treat icons as part of the placemark used for collision detection.
Previously icons were shown in any case, leading to a crowded appearance when many overlap. Now they are only shown when there is enough room for them. The old behavior (popular placemarks appear first, show label only if there is room for it) is kept. There is a potential follow-up tasks: Instead of a "winner takes it all" approach, group icons into a "group of placemarks" icon to indicate there is more to show when zooming in. The current approach allows to integrate that somewhat easily, however the user interaction needs to be changed acoordingly. Please review/test especially for map themes like Atlas. The new behavior seems fine to me, but I might miss some cases. CCMAIL: tackat@kde.org
-rw-r--r--src/lib/marble/PlacemarkLayout.cpp71
-rw-r--r--src/lib/marble/PlacemarkLayout.h3
-rw-r--r--src/lib/marble/VisiblePlacemark.cpp16
-rw-r--r--src/lib/marble/VisiblePlacemark.h4
4 files changed, 58 insertions, 36 deletions
diff --git a/src/lib/marble/PlacemarkLayout.cpp b/src/lib/marble/PlacemarkLayout.cpp
index b700d67..1c6ace1 100644
--- a/src/lib/marble/PlacemarkLayout.cpp
+++ b/src/lib/marble/PlacemarkLayout.cpp
@@ -44,14 +44,14 @@
namespace
{ //Helper function that checks for available room for the label
- bool hasRoomFor(const QVector<Marble::VisiblePlacemark*> & placemarks, const QRectF &labelRect)
+ bool hasRoomFor(const QVector<Marble::VisiblePlacemark*> & placemarks, const QRectF &boundingBox)
{
// Check if there is another label or symbol that overlaps.
QVector<Marble::VisiblePlacemark*>::const_iterator beforeItEnd = placemarks.constEnd();
for ( QVector<Marble::VisiblePlacemark*>::ConstIterator beforeIt = placemarks.constBegin();
beforeIt != beforeItEnd; ++beforeIt )
{
- if ( labelRect.intersects( (*beforeIt)->labelRect() ) ) {
+ if ( boundingBox.intersects( (*beforeIt)->boundingBox() ) ) {
return false;
}
}
@@ -517,6 +517,10 @@ bool PlacemarkLayout::layoutPlacemark( const GeoDataPlacemark *placemark, qreal
// Choose Section
+ QPointF hotSpot = mark->hotSpot();
+ mark->setSelected(selected);
+ mark->setSymbolPosition(QPoint(qRound(x - hotSpot.x()), qRound(y - hotSpot.y())));
+
// Find out whether the area around the placemark is covered already.
// If there's not enough space free don't add a VisiblePlacemark here.
@@ -524,36 +528,29 @@ bool PlacemarkLayout::layoutPlacemark( const GeoDataPlacemark *placemark, qreal
const QString labelText = placemark->displayName();
if (!labelText.isEmpty()) {
- labelRect = roomForLabel(style, x, y, labelText);
- if ( labelRect.isNull() ) {
- return false;
- }
+ labelRect = roomForLabel(style, x, y, labelText, mark);
}
-
- // Finally save the label position on the map.
- QPointF hotSpot = mark->hotSpot();
-
- if( mark->selected() != selected ) {
- mark->setSelected( selected );
+ if (labelRect.isNull() && (mark->symbolPixmap().isNull() || !hasRoomForPixmap(y, mark))) {
+ return false;
}
- mark->setSymbolPosition(QPoint(qRound(x - hotSpot.x()),
- qRound(y - hotSpot.y())));
- mark->setLabelRect( labelRect );
- if ( !labelRect.isEmpty() ) {
- // Add the current placemark to the matching row and its
- // direct neighbors.
- int idx = y / m_maxLabelHeight;
- if ( idx - 1 >= 0 )
- m_rowsection[ idx - 1 ].append( mark );
- m_rowsection[ idx ].append( mark );
- if ( idx + 1 < m_rowsection.size() )
- m_rowsection[ idx + 1 ].append( mark );
+ mark->setLabelRect( labelRect );
+ // Add the current placemark to the matching row and its
+ // direct neighbors.
+ int idx = y / m_maxLabelHeight;
+ if ( idx - 1 >= 0 ) {
+ m_rowsection[ idx - 1 ].append( mark );
+ }
+ m_rowsection[ idx ].append( mark );
+ if ( idx + 1 < m_rowsection.size() ) {
+ m_rowsection[ idx + 1 ].append( mark );
}
m_paintOrder.append( mark );
- m_labelArea += labelRect.width() * labelRect.height();
- m_maxLabelHeight = qMax(m_maxLabelHeight, qCeil(labelRect.height()));
+ QRectF const boundingBox = mark->boundingBox();
+ Q_ASSERT(!boundingBox.isEmpty());
+ m_labelArea += boundingBox.width() * boundingBox.height();
+ m_maxLabelHeight = qMax(m_maxLabelHeight, qCeil(boundingBox.height()));
return true;
}
@@ -571,7 +568,8 @@ GeoDataCoordinates PlacemarkLayout::placemarkIconCoordinates( const GeoDataPlace
QRectF PlacemarkLayout::roomForLabel( const GeoDataStyle::ConstPtr &style,
const qreal x, const qreal y,
- const QString &labelText ) const
+ const QString &labelText,
+ const VisiblePlacemark* placemark) const
{
QFont labelFont = style->labelStyle().scaledFont();
int textHeight = QFontMetrics( labelFont ).height();
@@ -586,6 +584,7 @@ QRectF PlacemarkLayout::roomForLabel( const GeoDataStyle::ConstPtr &style,
}
const QVector<VisiblePlacemark*> currentsec = m_rowsection.at( y / m_maxLabelHeight );
+ QRectF const symbolRect = placemark->symbolRect();
if ( style->labelStyle().alignment() == GeoDataLabelStyle::Corner ) {
const int symbolWidth = style->iconStyle().scaledIcon().size().width();
@@ -598,7 +597,7 @@ QRectF PlacemarkLayout::roomForLabel( const GeoDataStyle::ConstPtr &style,
y - textHeight;
const QRectF labelRect = QRectF( xPos, yPos, textWidth, textHeight );
- if (hasRoomFor(currentsec, labelRect)) {
+ if (hasRoomFor(currentsec, labelRect.united(symbolRect))) {
// claim the place immediately if it hasn't been used yet
return labelRect;
}
@@ -606,10 +605,10 @@ QRectF PlacemarkLayout::roomForLabel( const GeoDataStyle::ConstPtr &style,
}
else if ( style->labelStyle().alignment() == GeoDataLabelStyle::Center ) {
int const offsetY = style->iconStyle().scaledIcon().height() / 2.0;
- QRectF labelRect( x - textWidth / 2, y - offsetY - textHeight,
+ QRectF labelRect = QRectF( x - textWidth / 2, y - offsetY - textHeight,
textWidth, textHeight );
- if (hasRoomFor(currentsec, labelRect)) {
+ if (hasRoomFor(currentsec, labelRect.united(symbolRect))) {
// claim the place immediately if it hasn't been used yet
return labelRect;
}
@@ -629,15 +628,21 @@ QRectF PlacemarkLayout::roomForLabel( const GeoDataStyle::ConstPtr &style,
const QRectF labelRect = QRectF(xPos, yPos, textWidth, textHeight);
- if (hasRoomFor(currentsec, labelRect))
+ if (hasRoomFor(currentsec, labelRect.united(symbolRect)))
{
return labelRect;
}
}
}
- return QRectF(); // At this point there is no space left
- // for the rectangle anymore.
+ // At this point there is no space left for the rectangle anymore.
+ return QRectF();
+}
+
+bool PlacemarkLayout::hasRoomForPixmap(const qreal y, const VisiblePlacemark *placemark) const
+{
+ const QVector<VisiblePlacemark*> currentsec = m_rowsection.at(y / m_maxLabelHeight);
+ return hasRoomFor(currentsec, placemark->symbolRect());
}
bool PlacemarkLayout::placemarksOnScreenLimit( const QSize &screenSize ) const
diff --git a/src/lib/marble/PlacemarkLayout.h b/src/lib/marble/PlacemarkLayout.h
index 7ed8fa8..5035a2f 100644
--- a/src/lib/marble/PlacemarkLayout.h
+++ b/src/lib/marble/PlacemarkLayout.h
@@ -125,7 +125,8 @@ class PlacemarkLayout : public QObject
QRectF roomForLabel(const GeoDataStyle::ConstPtr &style,
const qreal x, const qreal y,
- const QString &labelText ) const;
+ const QString &labelText , const VisiblePlacemark *placemark) const;
+ bool hasRoomForPixmap(const qreal y, const VisiblePlacemark *placemark) const;
bool placemarksOnScreenLimit( const QSize &screenSize ) const;
diff --git a/src/lib/marble/VisiblePlacemark.cpp b/src/lib/marble/VisiblePlacemark.cpp
index d057a94..9ad5cd7 100644
--- a/src/lib/marble/VisiblePlacemark.cpp
+++ b/src/lib/marble/VisiblePlacemark.cpp
@@ -56,8 +56,10 @@ bool VisiblePlacemark::selected() const
void VisiblePlacemark::setSelected( bool selected )
{
- m_selected = selected;
- drawLabelPixmap();
+ if (selected != m_selected) {
+ m_selected = selected;
+ drawLabelPixmap();
+ }
}
const QPoint& VisiblePlacemark::symbolPosition() const
@@ -143,6 +145,16 @@ GeoDataStyle::ConstPtr VisiblePlacemark::style() const
return m_style;
}
+QRectF VisiblePlacemark::symbolRect() const
+{
+ return QRectF(m_symbolPosition, m_symbolPixmap.size());
+}
+
+QRectF VisiblePlacemark::boundingBox() const
+{
+ return m_labelRect.isEmpty() ? symbolRect() : m_labelRect.united(symbolRect());
+}
+
void VisiblePlacemark::drawLabelPixmap()
{
QString labelName = m_placemark->displayName();
diff --git a/src/lib/marble/VisiblePlacemark.h b/src/lib/marble/VisiblePlacemark.h
index 538ee62..1c8b4cd 100644
--- a/src/lib/marble/VisiblePlacemark.h
+++ b/src/lib/marble/VisiblePlacemark.h
@@ -104,6 +104,10 @@ class VisiblePlacemark : public QObject
GeoDataStyle::ConstPtr style() const;
+ QRectF symbolRect() const;
+
+ QRectF boundingBox() const;
+
Q_SIGNALS:
void updateNeeded();