Commit ae7ac56e authored by Dennis Nienhüser's avatar Dennis Nienhüser

More flexible rendering order in GeometryLayer/GeoGraphicsScene

The Vector OSM map theme has some rendering order problems right now
that result in some item combinations to look odd. This patch provides
a more fine-granular control of the rendering order. It also refactors
the decorators previously used and merges them into that approach.

Extend paint() of GeographicsItem to take another argument, a string
layer
Each GeographicsItem specifies a list of such layers it wants to paint
GeometryLayer defines the order of layers and paints them that way
E.g. currently a highway behaves like this:

GeoLineStringItem is created, and internally creates a copy of itself
which is its decorator, assigns a z-value
GeometryLayer queries all decorators during paint, sorts them by z-value
GeoLineStringItem tests whether it is a decorator during painting,
changes rendering based on that
The patch changes this to

GeoLineStringItem is created and asks for three layers to be rendered:
.../outline, .../inline and .../label
GeometryLayer queries all layers during paint, sorts them by render
order
GeoLineStringItem changes rendering based on the provided layer name
This avoids having to treat decorators as special and duplicated items
internally, and also allows an important render order behavior change:
It is now possible to render e.g. all visible streets first and all
their labels afterwards. Previously it was only possible to render one
street after the other, so e.g. the second street could overpaint the
label of the first.

Projects: #marble

Differential Revision: https://phabricator.kde.org/D1181
parent 5ddef264
......@@ -629,6 +629,8 @@ class GEODATA_EXPORT GeoDataFeature : public GeoDataObject
static QSharedPointer<Marble::GeoDataStyle> presetStyle( GeoDataVisualCategory category );
static QString visualCategoryName(GeoDataVisualCategory category);
virtual void detach();
protected:
......
......@@ -16,6 +16,7 @@
#include "GeoPainter.h"
#include "ViewportParams.h"
#include "GeoDataStyle.h"
#include "MarbleDebug.h"
namespace Marble
{
......@@ -25,43 +26,107 @@ GeoLineStringGraphicsItem::GeoLineStringGraphicsItem( const GeoDataFeature *feat
: GeoGraphicsItem( feature ),
m_lineString( lineString )
{
QString const category = GeoDataFeature::visualCategoryName(feature->visualCategory());
QStringList paintLayers;
paintLayers << QString("LineString/%1/outline").arg(category);
paintLayers << QString("LineString/%1/inline").arg(category);
paintLayers << QString("LineString/%1/label").arg(category);
setPaintLayers(paintLayers);
}
const float GeoLineStringGraphicsItem::s_outlineZValue = -0.001;
void GeoLineStringGraphicsItem::setLineString( const GeoDataLineString* lineString )
{
m_lineString = lineString;
}
void GeoLineStringGraphicsItem::createDecorations()
const GeoDataLatLonAltBox& GeoLineStringGraphicsItem::latLonAltBox() const
{
if ( style() != nullptr ) {
if ( style()->lineStyle().cosmeticOutline() ) {
GeoLineStringGraphicsItem* outline = new GeoLineStringGraphicsItem(this->feature(), this->m_lineString);
outline->setZValue(this->zValue() + s_outlineZValue);
return m_lineString->latLonAltBox();
}
this->addDecoration(outline);
}
void GeoLineStringGraphicsItem::paint(GeoPainter* painter, const ViewportParams* viewport , const QString &layer)
{
if (layer.endsWith("/outline")) {
paintOutline(painter, viewport);
} else if (layer.endsWith("/label")) {
paintLabel(painter, viewport);
} else if (layer.endsWith("/inline")) {
paintInline(painter, viewport);
} else {
painter->drawPolyline(*m_lineString);
}
}
void GeoLineStringGraphicsItem::setLineString( const GeoDataLineString* lineString )
void GeoLineStringGraphicsItem::paintInline(GeoPainter* painter, const ViewportParams* viewport)
{
m_lineString = lineString;
if ( ( !viewport->resolves( m_lineString->latLonAltBox(), 2) ) ) {
return;
}
painter->save();
LabelPositionFlags labelPositionFlags = NoLabel;
QPen currentPen = configurePainter(painter, viewport, labelPositionFlags);
if ( ! ( currentPen.widthF() < 2.5f ) ) {
if( style()->lineStyle().cosmeticOutline() &&
style()->lineStyle().penStyle() == Qt::SolidLine ) {
if ( currentPen.widthF() > 2.5f ) {
currentPen.setWidthF( currentPen.widthF() - 2.0f );
}
currentPen.setColor( style()->polyStyle().paintedColor() );
painter->setPen( currentPen );
painter->drawPolyline(*m_lineString);
} else {
painter->drawPolyline(*m_lineString);
}
}
painter->restore();
}
const GeoDataLatLonAltBox& GeoLineStringGraphicsItem::latLonAltBox() const
void GeoLineStringGraphicsItem::paintOutline(GeoPainter *painter, const ViewportParams *viewport)
{
return m_lineString->latLonAltBox();
if ( ( !viewport->resolves( m_lineString->latLonAltBox(), 2) ) ) {
return;
}
painter->save();
LabelPositionFlags labelPositionFlags = NoLabel;
QPen currentPen = configurePainter(painter, viewport, labelPositionFlags);
if (!( currentPen.widthF() < 2.5f )) {
painter->drawPolyline(*m_lineString);
}
painter->restore();
}
void GeoLineStringGraphicsItem::paint( GeoPainter* painter, const ViewportParams* viewport )
void GeoLineStringGraphicsItem::paintLabel(GeoPainter *painter, const ViewportParams *viewport)
{
if ( ( !viewport->resolves( m_lineString->latLonAltBox(), 2) ) ) {
return;
}
painter->save();
LabelPositionFlags labelPositionFlags = NoLabel;
QPen currentPen = configurePainter(painter, viewport, labelPositionFlags);
if (!( currentPen.widthF() < 2.5f )) {
QPen pen(QColor(Qt::transparent));
pen.setWidthF(currentPen.widthF());
painter->setPen(pen);
QColor const color = style()->polyStyle().paintedColor();
painter->setBackground(QBrush(color));
painter->setBackgroundMode(Qt::OpaqueMode);
painter->drawPolyline( *m_lineString, feature()->name(), FollowLine,
style()->labelStyle().paintedColor(),
style()->labelStyle().font());
}
painter->save();
painter->restore();
}
QPen GeoLineStringGraphicsItem::configurePainter(GeoPainter *painter, const ViewportParams *viewport, LabelPositionFlags &labelPositionFlags) const
{
QPen currentPen = painter->pen();
if ( !style() ) {
painter->setPen( QPen() );
......@@ -122,30 +187,7 @@ void GeoLineStringGraphicsItem::paint( GeoPainter* painter, const ViewportParams
}
}
if ( ! ( isDecoration() && currentPen.widthF() < 2.5f ) )
{
if( style()->lineStyle().cosmeticOutline() &&
style()->lineStyle().penStyle() == Qt::SolidLine ) {
if ( isDecoration() ) {
painter->drawPolyline( *m_lineString, "", NoLabel );
} else {
if ( currentPen.widthF() > 2.5f ) {
currentPen.setWidthF( currentPen.widthF() - 2.0f );
}
currentPen.setColor( style()->polyStyle().paintedColor() );
painter->setPen( currentPen );
painter->drawPolyline( *m_lineString, feature()->name(), FollowLine,
style()->labelStyle().paintedColor(),
style()->labelStyle().font());
}
} else {
painter->drawPolyline( *m_lineString, feature()->name(), labelPositionFlags,
style()->labelStyle().paintedColor(),
style()->labelStyle().font() );
}
}
painter->restore();
return currentPen;
}
}
......@@ -29,13 +29,18 @@ public:
virtual const GeoDataLatLonAltBox& latLonAltBox() const;
virtual void paint( GeoPainter* painter, const ViewportParams *viewport );
void paint(GeoPainter* painter, const ViewportParams *viewport, const QString &layer);
protected:
const GeoDataLineString *m_lineString;
static const float s_outlineZValue;
virtual void createDecorations();
private:
void paintOutline(GeoPainter *painter, const ViewportParams *viewport);
void paintInline(GeoPainter *painter, const ViewportParams *viewport);
void paintLabel(GeoPainter *painter, const ViewportParams *viewport);
QPen configurePainter(GeoPainter* painter, const ViewportParams *viewport, LabelPositionFlags &labelPositionFlags) const;
};
}
......
......@@ -12,6 +12,7 @@
#include "GeoPainter.h"
#include "GeoDataStyle.h"
#include "GeoDataFeature.h"
#include "ViewportParams.h"
#include <QImageReader>
......@@ -24,10 +25,15 @@ namespace Marble
GeoPhotoGraphicsItem::GeoPhotoGraphicsItem( const GeoDataFeature *feature )
: GeoGraphicsItem( feature )
{
if (feature) {
QString const paintLayer = QString("Photo/%1").arg(GeoDataFeature::visualCategoryName(feature->visualCategory()));
setPaintLayers(QStringList() << paintLayer);
}
}
void GeoPhotoGraphicsItem::paint( GeoPainter* painter, const ViewportParams* viewport )
void GeoPhotoGraphicsItem::paint(GeoPainter* painter, const ViewportParams* viewport , const QString &layer)
{
Q_UNUSED(layer);
/* The code below loads the image lazily (only
* when it will actually be displayed). Once it was
* loaded but moves out of the viewport, it is unloaded
......
......@@ -29,7 +29,7 @@ public:
GeoDataPoint point() const;
virtual void paint( GeoPainter* painter, const ViewportParams *viewport );
virtual void paint(GeoPainter* painter, const ViewportParams *viewport, const QString &layer);
virtual const GeoDataLatLonAltBox& latLonAltBox() const;
......
......@@ -11,6 +11,7 @@
#include "GeoPointGraphicsItem.h"
#include "GeoPainter.h"
#include "GeoDataFeature.h"
namespace Marble
{
......@@ -18,6 +19,10 @@ namespace Marble
GeoPointGraphicsItem::GeoPointGraphicsItem( const GeoDataFeature *feature )
: GeoGraphicsItem( feature )
{
if (feature) {
QString const paintLayer = QString("Point/%1").arg(GeoDataFeature::visualCategoryName(feature->visualCategory()));
setPaintLayers(QStringList() << paintLayer);
}
}
void GeoPointGraphicsItem::setPoint( const GeoDataPoint& point )
......@@ -30,9 +35,10 @@ GeoDataPoint GeoPointGraphicsItem::point() const
return m_point;
}
void GeoPointGraphicsItem::paint( GeoPainter* painter, const ViewportParams* viewport )
void GeoPointGraphicsItem::paint(GeoPainter* painter, const ViewportParams* viewport , const QString &layer)
{
Q_UNUSED( viewport );
Q_UNUSED(viewport);
Q_UNUSED(layer);
painter->drawPoint( m_point );
}
......
......@@ -27,7 +27,7 @@ public:
void setPoint( const GeoDataPoint& point );
GeoDataPoint point() const;
virtual void paint( GeoPainter* painter, const ViewportParams *viewport );
virtual void paint(GeoPainter* painter, const ViewportParams *viewport, const QString &layer);
virtual const GeoDataLatLonAltBox& latLonAltBox() const;
......
......@@ -32,19 +32,24 @@ public:
virtual const GeoDataLatLonAltBox& latLonAltBox() const;
virtual void paint( GeoPainter* painter, const ViewportParams *viewport );
protected:
virtual void createDecorations();
void paint(GeoPainter* painter, const ViewportParams *viewport, const QString &layer);
private:
void paintFrame( GeoPainter* painter, const ViewportParams *viewport );
void paintRoof( GeoPainter* painter, const ViewportParams *viewport );
QPointF buildingOffset(const QPointF &point, const ViewportParams *viewport, bool* isCameraAboveBuilding=0) const;
double extractBuildingHeight(double defaultValue) const;
void screenPolygons(const ViewportParams *viewport, const GeoDataPolygon* polygon, QVector<QPolygonF*> &polygons, QVector<QPolygonF*> &outlines);
void screenPolygons(const ViewportParams *viewport, const GeoDataPolygon* polygon, QVector<QPolygonF*> &polygons, QVector<QPolygonF*> &outlines) const;
QPen configurePainter(GeoPainter* painter, const ViewportParams *viewport, bool isBuildingFrame);
void determineBuildingHeight();
void initializeBuildingPainting(const GeoPainter* painter, const ViewportParams *viewport,
bool &drawAccurate3D, bool &isCameraAboveBuilding, bool &hasInnerBoundaries,
QVector<QPolygonF*>& outlinePolygons,
QVector<QPolygonF*>& innerPolygons) const;
const GeoDataPolygon *const m_polygon;
const GeoDataLinearRing *const m_ring;
static const float s_decorationZValue;
double m_buildingHeight;
QString m_cachedTexturePath;
QColor m_cachedTextureColor;
......
......@@ -12,6 +12,7 @@
#include "GeoDataLineString.h"
#include "GeoDataTrack.h"
#include "GeoDataFeature.h"
#include "MarbleDebug.h"
using namespace Marble;
......@@ -20,6 +21,10 @@ GeoTrackGraphicsItem::GeoTrackGraphicsItem( const GeoDataFeature *feature, const
: GeoLineStringGraphicsItem( feature, track->lineString() )
{
setTrack( track );
if (feature) {
QString const paintLayer = QString("Track/%1").arg(GeoDataFeature::visualCategoryName(feature->visualCategory()));
setPaintLayers(QStringList() << paintLayer);
}
}
void GeoTrackGraphicsItem::setTrack( const GeoDataTrack* track )
......@@ -28,11 +33,11 @@ void GeoTrackGraphicsItem::setTrack( const GeoDataTrack* track )
update();
}
void GeoTrackGraphicsItem::paint( GeoPainter *painter, const ViewportParams *viewport )
void GeoTrackGraphicsItem::paint(GeoPainter *painter, const ViewportParams *viewport , const QString &layer)
{
Q_UNUSED(layer);
update();
GeoLineStringGraphicsItem::paint( painter, viewport );
GeoLineStringGraphicsItem::paint(painter, viewport, layer);
}
void GeoTrackGraphicsItem::update()
......
......@@ -26,7 +26,7 @@ public:
void setTrack( const GeoDataTrack *track );
virtual void paint( GeoPainter *painter, const ViewportParams *viewport );
virtual void paint(GeoPainter *painter, const ViewportParams *viewport, const QString &layer);
private:
const GeoDataTrack *m_track;
......
......@@ -29,7 +29,6 @@ GeoGraphicsItem::GeoGraphicsItem( const GeoDataFeature *feature )
GeoGraphicsItem::~GeoGraphicsItem()
{
qDeleteAll< QList<GeoGraphicsItem*> >(d->m_decorations);
delete d;
}
......@@ -41,9 +40,6 @@ bool GeoGraphicsItem::visible() const
void GeoGraphicsItem::setVisible( bool visible )
{
setFlag( ItemIsVisible, visible );
foreach( GeoGraphicsItem* decoration, d->m_decorations ) {
decoration->setVisible( visible );
}
}
GeoGraphicsItem::GeoGraphicsItemFlags GeoGraphicsItem::flags() const
......@@ -78,17 +74,11 @@ const GeoDataLatLonAltBox& GeoGraphicsItem::latLonAltBox() const
void GeoGraphicsItem::setLatLonAltBox( const GeoDataLatLonAltBox& latLonAltBox )
{
d->m_latLonAltBox = latLonAltBox;
foreach( GeoGraphicsItem* decoration, d->m_decorations ) {
decoration->setLatLonAltBox( latLonAltBox );
}
}
void GeoGraphicsItem::setStyle( const GeoDataStyle::ConstPtr &style )
{
d->m_style = style;
foreach( GeoGraphicsItem* decoration, d->m_decorations ) {
decoration->setStyle( style );
}
}
void GeoGraphicsItem::setHighlightStyle( const GeoDataStyle::ConstPtr &highlightStyle)
......@@ -98,9 +88,6 @@ void GeoGraphicsItem::setHighlightStyle( const GeoDataStyle::ConstPtr &highlight
* and assign the new style @highlightStyle
*/
d->m_highlightStyle = highlightStyle;
foreach( GeoGraphicsItem* decoration, d->m_decorations ) {
decoration->setHighlightStyle( highlightStyle );
}
}
GeoDataStyle::ConstPtr GeoGraphicsItem::style() const
......@@ -128,9 +115,6 @@ void GeoGraphicsItem::setZValue( qreal z )
void GeoGraphicsItem::setHighlighted( bool highlight )
{
d->m_highlighted = highlight;
foreach( GeoGraphicsItem* decoration, d->m_decorations ) {
decoration->setHighlighted( highlight );
}
}
bool GeoGraphicsItem::isHighlighted() const
......@@ -138,47 +122,24 @@ bool GeoGraphicsItem::isHighlighted() const
return d->m_highlighted;
}
int GeoGraphicsItem::minZoomLevel() const
{
return d->m_minZoomLevel;
}
void GeoGraphicsItem::setMinZoomLevel(int zoomLevel)
QStringList GeoGraphicsItem::paintLayers() const
{
d->m_minZoomLevel = zoomLevel;
foreach( GeoGraphicsItem* decoration, d->m_decorations ) {
decoration->setMinZoomLevel( zoomLevel );
}
return d->m_paintLayers;
}
const QList<GeoGraphicsItem*>& GeoGraphicsItem::decorations()
void GeoGraphicsItem::setPaintLayers(const QStringList &paintLayers)
{
if ( d->m_decorations.isEmpty() ) {
createDecorations();
}
return d->m_decorations;
d->m_paintLayers = paintLayers;
}
void GeoGraphicsItem::addDecoration(GeoGraphicsItem* decoration)
int GeoGraphicsItem::minZoomLevel() const
{
if (decoration != nullptr) {
decoration->d->m_isDecoration = true;
decoration->setLatLonAltBox(this->latLonAltBox());
decoration->setFlags(this->flags());
decoration->setHighlighted(this->isHighlighted());
decoration->setStyle(this->style());
decoration->setMinZoomLevel(this->minZoomLevel());
decoration->setVisible(this->visible());
d->m_decorations.append(decoration);
}
return d->m_minZoomLevel;
}
bool GeoGraphicsItem::isDecoration() const
void GeoGraphicsItem::setMinZoomLevel(int zoomLevel)
{
return d->m_isDecoration;
d->m_minZoomLevel = zoomLevel;
}
bool GeoGraphicsItem::zValueLessThan(GeoGraphicsItem *one, GeoGraphicsItem *two)
......@@ -186,7 +147,3 @@ bool GeoGraphicsItem::zValueLessThan(GeoGraphicsItem *one, GeoGraphicsItem *two)
return one->d->m_zValue < two->d->m_zValue;
}
void GeoGraphicsItem::createDecorations()
{
return;
}
......@@ -126,31 +126,18 @@ class MARBLE_EXPORT GeoGraphicsItem
* Note that depending on the projection and zoom level, the item may be visible more than once,
* which is taken care of by GeoPainter.
*/
virtual void paint( GeoPainter *painter, const ViewportParams *viewport ) = 0;
virtual void paint(GeoPainter *painter, const ViewportParams *viewport, const QString &layer) = 0;
void setHighlighted( bool highlight );
bool isHighlighted() const;
const QList<GeoGraphicsItem*>& decorations();
QStringList paintLayers() const;
bool isDecoration() const;
void setPaintLayers(const QStringList &paintLayers);
protected:
GeoGraphicsItemPrivate *const d;
/**
* Creates a new decoration for this item.
*
* Override this function to create a new type of decoration,
* e.g. outlines for lines or "fake 3D effect" for polygons.
* After a decoration was created add it to the item with
* addDecoration(). You can create multiple decoration for a
* single GeoGraphicsItem.
*/
virtual void createDecorations();
void addDecoration(GeoGraphicsItem* decoration);
};
} // Namespace Marble
......
......@@ -28,7 +28,6 @@ class GeoGraphicsItemPrivate
m_minZoomLevel( 0 ),
m_feature( feature ),
m_latLonAltBox(),
m_isDecoration( false ),
m_highlighted( false )
{
}
......@@ -45,8 +44,7 @@ class GeoGraphicsItemPrivate
GeoDataLatLonAltBox m_latLonAltBox;
GeoDataStyle::ConstPtr m_style;
bool m_isDecoration;
QList<GeoGraphicsItem*> m_decorations;
QStringList m_paintLayers;
// To highlight a placemark
bool m_highlighted;
......
This diff is collapsed.
......@@ -241,7 +241,7 @@ bool AnnotatePlugin::render( GeoPainter *painter, ViewportParams *viewport, cons
QListIterator<SceneGraphicsItem*> iter( m_graphicsItems );
while ( iter.hasNext() ) {
iter.next()->paint( painter, viewport );
iter.next()->paint( painter, viewport, "Annotation" );
}
return true;
......
......@@ -51,7 +51,7 @@ AreaAnnotation::AreaAnnotation( GeoDataPlacemark *placemark ) :
m_interactingObj( InteractingNothing ),
m_virtualHovered( -1, -1 )
{
// nothing to do
setPaintLayers(QStringList() << "AreaAnnotation");
}
AreaAnnotation::~AreaAnnotation()
......@@ -59,8 +59,9 @@ AreaAnnotation::~AreaAnnotation()
delete m_animation;
}
void AreaAnnotation::paint( GeoPainter *painter, const ViewportParams *viewport )
void AreaAnnotation::paint(GeoPainter *painter, const ViewportParams *viewport , const QString &layer)
{
Q_UNUSED(layer);
m_viewport = viewport;
Q_ASSERT( placemark()->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType );
......
......@@ -43,7 +43,7 @@ public:
* @brief Paints the nodes on the screen and updates the regions which correspond
* to each node using the given GeoPainter.
*/
virtual void paint( GeoPainter *painter, const ViewportParams *viewport );
virtual void paint( GeoPainter *painter, const ViewportParams *viewport, const QString &layer );
/**
* @brief Returns true if the given QPoint is contained by the current polygon. Note
......
......@@ -91,10 +91,12 @@ GroundOverlayFrame::GroundOverlayFrame( GeoDataPlacemark *placemark,
m_rotateIcons.append( QImage( MarbleDirs::systemPath() + "/bitmaps/editarrows/arrow-vertical-active.png" ) );
update();
setPaintLayers(QStringList() << "GroundOverlayFrame");
}
void GroundOverlayFrame::paint(GeoPainter *painter, const ViewportParams *viewport )
void GroundOverlayFrame::paint(GeoPainter *painter, const ViewportParams *viewport , const QString &layer)
{
Q_UNUSED(layer);
m_viewport = viewport;
m_regionList.clear();
......
......@@ -55,7 +55,7 @@ public:
virtual const char *graphicType() const;
protected:
virtual void paint( GeoPainter *painter, const ViewportParams *viewport );
virtual void paint( GeoPainter *painter, const ViewportParams *viewport, const QString &layer );
virtual bool mousePressEvent( QMouseEvent *event );
virtual bool mouseMoveEvent( QMouseEvent *event );
virtual bool mouseReleaseEvent( QMouseEvent *event );
......
......@@ -42,6 +42,7 @@ PlacemarkTextAnnotation::PlacemarkTextAnnotation( GeoDataPlacemark *placemark )
newStyle->iconStyle().setIconPath( MarbleDirs::path("bitmaps/redflag_22.png") );
placemark->setStyle( newStyle );
}
setPaintLayers(QStringList() << "PlacemarkTextAnnotation");
}
PlacemarkTextAnnotation::~PlacemarkTextAnnotation()
......@@ -49,8 +50,9 @@ PlacemarkTextAnnotation::~PlacemarkTextAnnotation()
// nothing to do
}
void PlacemarkTextAnnotation::paint( GeoPainter *painter, const ViewportParams *viewport )
void PlacemarkTextAnnotation::paint( GeoPainter *painter, const ViewportParams *viewport, const QString &layer )
{
Q_UNUSED(layer);
Q_UNUSED( painter );
m_viewport = viewport;
......