summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Nienhüser <nienhueser@kde.org>2016-11-08 21:12:01 (GMT)
committerDennis Nienhüser <nienhueser@kde.org>2016-11-08 21:12:01 (GMT)
commit3e8d79cd9fa5e15678fb0b281fd306b704f60b76 (patch)
treeccb41b2206f2192bdd55f491500938c545e2e262
parenta094ca0764777fb52f51740934f924ae82a113f2 (diff)
Merge line strings with equal osm ids that are split across tiles.
- Improves rendering since street names are better layed out and no false split indicators are drawn - Improves render performance (less items to paint) - Drawback of course is increased code complexity and a small overhead for merging strings. Seems reasonable though.
-rw-r--r--src/lib/marble/geodata/graphicsitem/GeoLineStringGraphicsItem.cpp89
-rw-r--r--src/lib/marble/geodata/graphicsitem/GeoLineStringGraphicsItem.h9
-rw-r--r--src/lib/marble/layers/GeometryLayer.cpp67
3 files changed, 153 insertions, 12 deletions
diff --git a/src/lib/marble/geodata/graphicsitem/GeoLineStringGraphicsItem.cpp b/src/lib/marble/geodata/graphicsitem/GeoLineStringGraphicsItem.cpp
index 907b8fe..6768614 100644
--- a/src/lib/marble/geodata/graphicsitem/GeoLineStringGraphicsItem.cpp
+++ b/src/lib/marble/geodata/graphicsitem/GeoLineStringGraphicsItem.cpp
@@ -20,6 +20,7 @@
#include "ViewportParams.h"
#include "GeoDataStyle.h"
#include "MarbleDebug.h"
+#include "MarbleMath.h"
#include <qmath.h>
@@ -29,7 +30,8 @@ namespace Marble
GeoLineStringGraphicsItem::GeoLineStringGraphicsItem(const GeoDataPlacemark *placemark,
const GeoDataLineString *lineString) :
GeoGraphicsItem(placemark),
- m_lineString(lineString)
+ m_lineString(lineString),
+ m_renderLineString(lineString)
{
QString const category = StyleBuilder::visualCategoryName(placemark->visualCategory());
QStringList paintLayers;
@@ -43,11 +45,75 @@ GeoLineStringGraphicsItem::GeoLineStringGraphicsItem(const GeoDataPlacemark *pla
void GeoLineStringGraphicsItem::setLineString( const GeoDataLineString* lineString )
{
m_lineString = lineString;
+ m_renderLineString = lineString;
+}
+
+const GeoDataLineString *GeoLineStringGraphicsItem::lineString() const
+{
+ return m_lineString;
+}
+
+GeoDataLineString GeoLineStringGraphicsItem::merge(const QVector<const GeoDataLineString *> &lineStrings_)
+{
+ if (lineStrings_.isEmpty()) {
+ return GeoDataLineString();
+ }
+
+ Q_ASSERT(!lineStrings_.isEmpty());
+ auto lineStrings = lineStrings_;
+ GeoDataLineString result = *lineStrings.first();
+ lineStrings.pop_front();
+ for (bool matched = true; matched && !lineStrings.isEmpty();) {
+ matched = false;
+ for (auto lineString: lineStrings) {
+ if (canMerge(result.first(), lineString->first())) {
+ result.remove(0);
+ result.reverse();
+ result << *lineString;
+ lineStrings.removeOne(lineString);
+ matched = true;
+ break;
+ } else if (canMerge(result.last(), lineString->first())) {
+ result.remove(result.size()-1);
+ result << *lineString;
+ lineStrings.removeOne(lineString);
+ matched = true;
+ break;
+ } else if (canMerge(result.first(), lineString->last())) {
+ GeoDataLineString behind = result;
+ result = *lineString;
+ behind.remove(0);
+ result << behind;
+ lineStrings.removeOne(lineString);
+ matched = true;
+ break;
+ } else if (canMerge(result.last(), lineString->last())) {
+ GeoDataLineString behind = *lineString;
+ behind.reverse();
+ behind.remove(0);
+ result << behind;
+ lineStrings.removeOne(lineString);
+ matched = true;
+ break;
+ }
+ }
+
+ if (!matched) {
+ return GeoDataLineString();
+ }
+ }
+ return lineStrings.isEmpty() ? result : GeoDataLineString();
+}
+
+void GeoLineStringGraphicsItem::setMergedLineString(const GeoDataLineString &mergedLineString)
+{
+ m_mergedLineString = mergedLineString;
+ m_renderLineString = mergedLineString.isEmpty() ? m_lineString : &m_mergedLineString;
}
const GeoDataLatLonAltBox& GeoLineStringGraphicsItem::latLonAltBox() const
{
- return m_lineString->latLonAltBox();
+ return m_renderLineString->latLonAltBox();
}
void GeoLineStringGraphicsItem::paint(GeoPainter* painter, const ViewportParams* viewport , const QString &layer)
@@ -64,13 +130,13 @@ void GeoLineStringGraphicsItem::paint(GeoPainter* painter, const ViewportParams*
} else if (layer.endsWith(QLatin1String("/inline"))) {
paintInline(painter, viewport);
} else {
- painter->drawPolyline(*m_lineString);
+ painter->drawPolyline(*m_renderLineString);
}
}
void GeoLineStringGraphicsItem::paintInline(GeoPainter* painter, const ViewportParams* viewport)
{
- if ( ( !viewport->resolves( m_lineString->latLonAltBox(), 2) ) ) {
+ if ( ( !viewport->resolves( m_renderLineString->latLonAltBox(), 2) ) ) {
return;
}
@@ -88,14 +154,14 @@ void GeoLineStringGraphicsItem::paintInline(GeoPainter* painter, const ViewportP
currentPen.setColor(style->polyStyle().paintedColor());
painter->setPen( currentPen );
}
- painter->drawPolyline(*m_lineString);
+ painter->drawPolyline(*m_renderLineString);
painter->restore();
}
void GeoLineStringGraphicsItem::paintOutline(GeoPainter *painter, const ViewportParams *viewport)
{
- if ( ( !viewport->resolves( m_lineString->latLonAltBox(), 2) ) ) {
+ if ( ( !viewport->resolves( m_renderLineString->latLonAltBox(), 2) ) ) {
return;
}
@@ -103,14 +169,14 @@ void GeoLineStringGraphicsItem::paintOutline(GeoPainter *painter, const Viewport
LabelPositionFlags labelPositionFlags = NoLabel;
QPen currentPen = configurePainter(painter, viewport, labelPositionFlags);
if (!( currentPen.widthF() < 2.5f )) {
- painter->drawPolyline(*m_lineString);
+ painter->drawPolyline(*m_renderLineString);
}
painter->restore();
}
void GeoLineStringGraphicsItem::paintLabel(GeoPainter *painter, const ViewportParams *viewport)
{
- if ( ( !viewport->resolves( m_lineString->latLonAltBox(), 2) ) ) {
+ if ( ( !viewport->resolves( m_renderLineString->latLonAltBox(), 2) ) ) {
return;
}
@@ -132,7 +198,7 @@ void GeoLineStringGraphicsItem::paintLabel(GeoPainter *painter, const ViewportPa
//painter->setBackgroundMode(Qt::OpaqueMode);
const GeoDataLabelStyle& labelStyle = style->labelStyle();
painter->setFont(labelStyle.font());
- painter->drawPolyline( *m_lineString, feature()->name(), FollowLine,
+ painter->drawPolyline( *m_renderLineString, feature()->name(), FollowLine,
labelStyle.paintedColor());
}
@@ -221,4 +287,9 @@ QPen GeoLineStringGraphicsItem::configurePainter(GeoPainter *painter, const View
return currentPen;
}
+bool GeoLineStringGraphicsItem::canMerge(const GeoDataCoordinates &a, const GeoDataCoordinates &b)
+{
+ return distanceSphere(a, b) * EARTH_RADIUS < 0.1;
+}
+
}
diff --git a/src/lib/marble/geodata/graphicsitem/GeoLineStringGraphicsItem.h b/src/lib/marble/geodata/graphicsitem/GeoLineStringGraphicsItem.h
index b64dbad..7217617 100644
--- a/src/lib/marble/geodata/graphicsitem/GeoLineStringGraphicsItem.h
+++ b/src/lib/marble/geodata/graphicsitem/GeoLineStringGraphicsItem.h
@@ -12,13 +12,14 @@
#define MARBLE_GEOLINESTRINGGRAPHICSITEM_H
#include "GeoGraphicsItem.h"
+#include "GeoDataCoordinates.h"
+#include "GeoDataLineString.h"
#include "MarbleGlobal.h"
#include "marble_export.h"
namespace Marble
{
-class GeoDataLineString;
class GeoDataPlacemark;
class MARBLE_EXPORT GeoLineStringGraphicsItem : public GeoGraphicsItem
@@ -27,6 +28,9 @@ public:
explicit GeoLineStringGraphicsItem(const GeoDataPlacemark *placemark, const GeoDataLineString *lineString);
void setLineString( const GeoDataLineString* lineString );
+ const GeoDataLineString* lineString() const;
+ static GeoDataLineString merge(const QVector<const GeoDataLineString*> &lineStrings);
+ void setMergedLineString(const GeoDataLineString &sharedLineString);
virtual const GeoDataLatLonAltBox& latLonAltBox() const;
@@ -37,8 +41,11 @@ private:
void paintInline(GeoPainter *painter, const ViewportParams *viewport);
void paintLabel(GeoPainter *painter, const ViewportParams *viewport);
QPen configurePainter(GeoPainter* painter, const ViewportParams *viewport, LabelPositionFlags &labelPositionFlags) const;
+ static bool canMerge(const GeoDataCoordinates &a, const GeoDataCoordinates &b);
const GeoDataLineString *m_lineString;
+ const GeoDataLineString *m_renderLineString;
+ GeoDataLineString m_mergedLineString;
};
}
diff --git a/src/lib/marble/layers/GeometryLayer.cpp b/src/lib/marble/layers/GeometryLayer.cpp
index 1798d37..72f77bb 100644
--- a/src/lib/marble/layers/GeometryLayer.cpp
+++ b/src/lib/marble/layers/GeometryLayer.cpp
@@ -61,6 +61,8 @@ namespace Marble
class GeometryLayerPrivate
{
public:
+ typedef QVector<GeoLineStringGraphicsItem*> OsmLineStringItems;
+
struct PaintFragments {
// Three lists for different z values
// A z value of 0 is default and used by the majority of items, so sorting
@@ -76,12 +78,16 @@ public:
void createGraphicsItemFromGeometry(const GeoDataGeometry *object, const GeoDataPlacemark *placemark);
void createGraphicsItemFromOverlay( const GeoDataOverlay *overlay );
void removeGraphicsItems( const GeoDataFeature *feature );
+ void updateTiledLineStrings(const GeoDataPlacemark *placemark, GeoLineStringGraphicsItem* lineStringItem);
+ void updateTiledLineStrings(OsmLineStringItems &lineStringItems);
const QAbstractItemModel *const m_model;
const StyleBuilder *const m_styleBuilder;
GeoGraphicsScene m_scene;
QString m_runtimeTrace;
QList<ScreenOverlayGraphicsItem*> m_items;
+
+ QHash<qint64,OsmLineStringItems> m_osmLineStringItems;
};
GeometryLayerPrivate::GeometryLayerPrivate(const QAbstractItemModel *model, const StyleBuilder *styleBuilder) :
@@ -219,6 +225,43 @@ void GeometryLayerPrivate::createGraphicsItems( const GeoDataObject *object )
}
}
+void GeometryLayerPrivate::updateTiledLineStrings(const GeoDataPlacemark* placemark, GeoLineStringGraphicsItem* lineStringItem)
+{
+ if (!placemark->hasOsmData()) {
+ return;
+ }
+ qint64 const osmId = placemark->osmData().id();
+ if (osmId <= 0) {
+ return;
+ }
+ auto & lineStringItems = m_osmLineStringItems[osmId];
+ lineStringItems << lineStringItem;
+ updateTiledLineStrings(lineStringItems);
+}
+
+void GeometryLayerPrivate::updateTiledLineStrings(OsmLineStringItems &lineStringItems)
+{
+ GeoDataLineString merged;
+ if (lineStringItems.size() > 1) {
+ QVector<const GeoDataLineString*> lineStrings;
+ for (auto item: lineStringItems) {
+ lineStrings << item->lineString();
+ }
+ merged = GeoLineStringGraphicsItem::merge(lineStrings);
+ }
+
+ // If merging failed, reset all. Otherwise only the first one
+ // gets the merge result and becomes visible.
+ bool visible = true;
+ for (auto item: lineStringItems) {
+ item->setVisible(visible);
+ if (visible) {
+ item->setMergedLineString(merged);
+ visible = merged.isEmpty();
+ }
+ }
+}
+
void GeometryLayerPrivate::createGraphicsItemFromGeometry(const GeoDataGeometry* object, const GeoDataPlacemark *placemark)
{
if (!placemark->isGloballyVisible()) {
@@ -229,7 +272,9 @@ void GeometryLayerPrivate::createGraphicsItemFromGeometry(const GeoDataGeometry*
if ( object->nodeType() == GeoDataTypes::GeoDataLineStringType )
{
const GeoDataLineString* line = static_cast<const GeoDataLineString*>( object );
- item = new GeoLineStringGraphicsItem( placemark, line );
+ auto lineStringItem = new GeoLineStringGraphicsItem( placemark, line );
+ item = lineStringItem;
+ updateTiledLineStrings(placemark, lineStringItem);
}
else if ( object->nodeType() == GeoDataTypes::GeoDataLinearRingType )
{
@@ -270,7 +315,7 @@ void GeometryLayerPrivate::createGraphicsItemFromGeometry(const GeoDataGeometry*
if ( !item )
return;
item->setStyleBuilder(m_styleBuilder);
- item->setVisible( placemark->isGloballyVisible() );
+ item->setVisible( item->visible() && placemark->isGloballyVisible() );
item->setMinZoomLevel(m_styleBuilder->minimumZoomLevel(*placemark));
m_scene.addItem( item );
}
@@ -304,6 +349,23 @@ void GeometryLayerPrivate::removeGraphicsItems( const GeoDataFeature *feature )
{
if( feature->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) {
+ GeoDataPlacemark const * placemark = static_cast<GeoDataPlacemark const *>(feature);
+ if (placemark->isGloballyVisible() &&
+ placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType &&
+ placemark->hasOsmData() &&
+ placemark->osmData().id() > 0) {
+ auto & items = m_osmLineStringItems[placemark->osmData().id()];
+ bool removed = false;
+ for (auto item: items) {
+ if (item->feature() == feature) {
+ items.removeOne(item);
+ removed = true;
+ break;
+ }
+ }
+ Q_ASSERT(removed);
+ updateTiledLineStrings(items);
+ }
m_scene.removeItem( feature );
}
else if( feature->nodeType() == GeoDataTypes::GeoDataFolderType
@@ -362,6 +424,7 @@ void GeometryLayer::resetCacheData()
d->m_scene.clear();
qDeleteAll( d->m_items );
d->m_items.clear();
+ d->m_osmLineStringItems.clear();
const GeoDataObject *object = static_cast<GeoDataObject*>( d->m_model->index( 0, 0, QModelIndex() ).internalPointer() );
if ( object && object->parent() )