Show a layer tree next to elevation profile plots

This:

- Allows users to turn on or off the visibility of layers from
the profile plot on a plot-by-plot basis (previously the layer
visibility was taken straight from the main canvas layer visibility)
- Allows users to rearrange the drawing order of layers in the plot
- Allows a shortcut to the layer elevation properties settings by
double clicking layers
- Provides a "legend" for the features visible on the plot
This commit is contained in:
Nyall Dawson 2022-04-18 13:05:24 +10:00
parent 7fa773e49e
commit c52b2d3ce4
14 changed files with 505 additions and 14 deletions

View File

@ -424,6 +424,8 @@ Filter nodes from :py:class:`QgsMapLayerLegend` according to the current filteri
};
QFlags<QgsLayerTreeModel::Flag> operator|(QgsLayerTreeModel::Flag f1, QFlags<QgsLayerTreeModel::Flag> f2);

View File

@ -175,6 +175,8 @@ set(QGIS_APP_SRCS
elevation/qgselevationprofileexportsettingswidget.cpp
elevation/qgselevationprofileimageexportdialog.cpp
elevation/qgselevationprofilelayertreemodel.cpp
elevation/qgselevationprofilelayertreeview.cpp
elevation/qgselevationprofilepdfexportdialog.cpp
elevation/qgselevationprofilewidget.cpp
elevation/qgsmaptoolprofilecurve.cpp

View File

@ -0,0 +1,208 @@
/***************************************************************************
qgselevationprofilelayertreemodel.cpp
-----------------
begin : April 2022
copyright : (C) 2022 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgselevationprofilelayertreemodel.h"
#include "qgslayertreenode.h"
#include "qgslayertree.h"
#include "qgssymbollayerutils.h"
#include "qgsvectorlayerelevationproperties.h"
#include "qgsmeshlayerelevationproperties.h"
#include "qgsrasterlayerelevationproperties.h"
#include "qgsvectorlayer.h"
#include "qgssinglesymbolrenderer.h"
#include "qgsmarkersymbol.h"
#include "qgsfillsymbol.h"
QgsElevationProfileLayerTreeModel::QgsElevationProfileLayerTreeModel( QgsLayerTree *rootNode, QObject *parent )
: QgsLayerTreeModel( rootNode, parent )
{
setFlag( QgsLayerTreeModel::AllowNodeReorder );
setFlag( QgsLayerTreeModel::AllowNodeChangeVisibility );
setFlag( QgsLayerTreeModel::ShowLegendAsTree );
setFlag( QgsLayerTreeModel::AllowLegendChangeState, false );
}
QVariant QgsElevationProfileLayerTreeModel::data( const QModelIndex &index, int role ) const
{
switch ( role )
{
case Qt::DecorationRole:
{
QgsLayerTreeNode *node = index2node( index );
if ( node && node->nodeType() == QgsLayerTreeNode::NodeLayer )
{
if ( QgsMapLayer *layer = QgsLayerTree::toLayer( node )->layer() )
{
std::unique_ptr<QgsRenderContext> context( createTemporaryRenderContext() );
const int iconSize = scaleIconSize( 16 );
std::unique_ptr< QgsSymbol > symbol;
switch ( layer->type() )
{
case QgsMapLayerType::VectorLayer:
{
QgsVectorLayerElevationProperties *elevationProperties = qgis::down_cast< QgsVectorLayerElevationProperties * >( layer->elevationProperties() );
QgsVectorLayer *vLayer = qobject_cast< QgsVectorLayer * >( layer );
if ( ( vLayer->geometryType() == QgsWkbTypes::PointGeometry && !elevationProperties->extrusionEnabled() )
|| ( vLayer->geometryType() == QgsWkbTypes::LineGeometry && !elevationProperties->extrusionEnabled() )
)
{
if ( QgsMarkerSymbol *markerSymbol = elevationProperties->profileMarkerSymbol() )
{
symbol.reset( markerSymbol->clone() );
}
}
if ( !symbol && vLayer->geometryType() == QgsWkbTypes::PolygonGeometry && elevationProperties->extrusionEnabled() )
{
if ( QgsFillSymbol *fillSymbol = elevationProperties->profileFillSymbol() )
{
symbol.reset( fillSymbol->clone() );
}
}
if ( !symbol )
{
if ( QgsLineSymbol *lineSymbol = elevationProperties->profileLineSymbol() )
{
symbol.reset( lineSymbol->clone() );
}
}
if ( qgis::down_cast< QgsVectorLayerElevationProperties * >( layer->elevationProperties() )->respectLayerSymbology() )
{
if ( QgsSingleSymbolRenderer *renderer = dynamic_cast< QgsSingleSymbolRenderer * >( qobject_cast< QgsVectorLayer * >( layer )->renderer() ) )
{
symbol->setColor( renderer->symbol()->color() );
symbol->setOpacity( renderer->symbol()->opacity() );
}
else
{
// just use default layer icon
return QgsLayerTreeModel::data( index, role );
}
}
break;
}
case QgsMapLayerType::RasterLayer:
if ( QgsLineSymbol *lineSymbol = qgis::down_cast< QgsRasterLayerElevationProperties * >( layer->elevationProperties() )->profileLineSymbol() )
{
symbol.reset( lineSymbol->clone() );
}
break;
case QgsMapLayerType::MeshLayer:
if ( QgsLineSymbol *lineSymbol = qgis::down_cast< QgsMeshLayerElevationProperties * >( layer->elevationProperties() )->profileLineSymbol() )
{
symbol.reset( lineSymbol->clone() );
}
break;
case QgsMapLayerType::PluginLayer:
case QgsMapLayerType::VectorTileLayer:
case QgsMapLayerType::AnnotationLayer:
case QgsMapLayerType::PointCloudLayer:
case QgsMapLayerType::GroupLayer:
break;
}
if ( !symbol )
break;
const QPixmap pix = QgsSymbolLayerUtils::symbolPreviewPixmap( symbol.get(), QSize( iconSize, iconSize ), 0, context.get() );
return QIcon( pix );
}
}
break;
}
default:
break;
}
return QgsLayerTreeModel::data( index, role );
}
//
// QgsElevationProfileLayerTreeProxyModel
//
QgsElevationProfileLayerTreeProxyModel::QgsElevationProfileLayerTreeProxyModel( QgsElevationProfileLayerTreeModel *model, QObject *parent )
: QSortFilterProxyModel( parent )
, mModel( model )
{
setSourceModel( mModel );
setDynamicSortFilter( true );
}
bool QgsElevationProfileLayerTreeProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
{
const QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent );
if ( QgsLayerTreeNode *node = mModel->index2node( sourceIndex ) )
{
switch ( node->nodeType() )
{
case QgsLayerTreeNode::NodeLayer:
{
if ( QgsLayerTreeLayer *layerTreeLayer = QgsLayerTree::toLayer( node ) )
{
if ( QgsMapLayer *layer = layerTreeLayer->layer() )
{
// hide layers which don't have elevation
if ( !layer->elevationProperties() || !layer->elevationProperties()->hasElevation() )
return false;
}
}
break;
}
case QgsLayerTreeNode::NodeGroup:
break;
}
return true;
}
else if ( QgsLayerTreeModelLegendNode *legendNode = mModel->index2legendNode( sourceIndex ) )
{
// we only show legend nodes for vector layers where the profile symbol is set to follow the layer's symbology
// (and the layer's renderer isn't a single symbol renderer)
if ( QgsLayerTreeLayer *layerTreeLayer = QgsLayerTree::toLayer( legendNode->layerNode() ) )
{
if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( layerTreeLayer->layer() ) )
{
if ( !qgis::down_cast< QgsVectorLayerElevationProperties * >( layer->elevationProperties() )->respectLayerSymbology() )
{
return false;
}
else if ( dynamic_cast< QgsSingleSymbolRenderer * >( qobject_cast< QgsVectorLayer * >( layer )->renderer() ) )
{
return false;
}
else
{
return true;
}
}
}
return false;
}
else
{
return false;
}
}

View File

@ -0,0 +1,82 @@
/***************************************************************************
qgselevationprofilelayertreemodel.h
---------------
begin : April 2022
copyright : (C) 2022 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSELEVATIONPROFILELAYERTREEMODEL_H
#define QGSELEVATIONPROFILELAYERTREEMODEL_H
#include "qgsconfig.h"
#include "qgslayertreemodel.h"
#include <QSortFilterProxyModel>
/**
* \ingroup app
* \brief A layer tree model subclass for elevation profiles.
*
* \since QGIS 3.26
*/
class QgsElevationProfileLayerTreeModel : public QgsLayerTreeModel
{
Q_OBJECT
public:
/**
* Construct a new tree model with given layer tree (root node must not be NULLPTR).
* The root node is not transferred by the model.
*/
explicit QgsElevationProfileLayerTreeModel( QgsLayerTree *rootNode, QObject *parent = nullptr );
QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override;
private:
#ifdef SIP_RUN
QgsElevationProfileLayerTreeModel( const QgsElevationProfileLayerTreeModel &other );
#endif
};
/**
* \ingroup gui
* \brief A proxy model for elevation profiles.
*
* \since QGIS 3.26
*/
class QgsElevationProfileLayerTreeProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
/**
* Constructor for QgsElevationProfileLayerTreeProxyModel.
*/
explicit QgsElevationProfileLayerTreeProxyModel( QgsElevationProfileLayerTreeModel *model, QObject *parent = nullptr );
protected:
bool filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const override;
private:
QgsElevationProfileLayerTreeModel *mModel = nullptr;
};
#endif // QGSELEVATIONPROFILELAYERTREEMODEL_H

View File

@ -0,0 +1,62 @@
/***************************************************************************
qgselevationprofilelayertreeview.cpp
-----------------
begin : April 2022
copyright : (C) 2022 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgselevationprofilelayertreeview.h"
#include "qgselevationprofilelayertreemodel.h"
#include "qgslayertreenode.h"
#include "qgslayertree.h"
#include <QHeaderView>
QgsElevationProfileLayerTreeView::QgsElevationProfileLayerTreeView( QgsLayerTree *rootNode, QWidget *parent )
: QTreeView( parent )
, mLayerTree( rootNode )
{
mModel = new QgsElevationProfileLayerTreeModel( rootNode, this );
mProxyModel = new QgsElevationProfileLayerTreeProxyModel( mModel, this );
setHeaderHidden( true );
setDragEnabled( true );
setAcceptDrops( true );
setDropIndicatorShown( true );
setExpandsOnDoubleClick( false );
// Ensure legend graphics are scrollable
header()->setStretchLastSection( false );
header()->setSectionResizeMode( QHeaderView::ResizeToContents );
// If vertically scrolling by item, legend graphics can get clipped
setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
setDefaultDropAction( Qt::MoveAction );
setModel( mProxyModel );
}
QgsMapLayer *QgsElevationProfileLayerTreeView::indexToLayer( const QModelIndex &index )
{
if ( QgsLayerTreeNode *node = mModel->index2node( mProxyModel->mapToSource( index ) ) )
{
if ( QgsLayerTreeLayer *layerTreeLayerNode = mLayerTree->toLayer( node ) )
{
return layerTreeLayerNode->layer();
}
}
return nullptr;
}

View File

@ -0,0 +1,63 @@
/***************************************************************************
qgselevationprofilelayertreeview.h
---------------
begin : April 2022
copyright : (C) 2022 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSELEVATIONPROFILELAYERTREEVIEW_H
#define QGSELEVATIONPROFILELAYERTREEVIEW_H
#include "qgsconfig.h"
#include <QTreeView>
class QgsLayerTree;
class QgsElevationProfileLayerTreeModel;
class QgsElevationProfileLayerTreeProxyModel;
class QgsMapLayer;
/**
* \ingroup app
* \brief A layer tree view for elevation profiles.
*
* \since QGIS 3.26
*/
class QgsElevationProfileLayerTreeView : public QTreeView
{
Q_OBJECT
public:
/**
* Construct a new tree view with given layer tree (root node must not be NULLPTR).
* The root node is not transferred by the view.
*/
explicit QgsElevationProfileLayerTreeView( QgsLayerTree *rootNode, QWidget *parent = nullptr );
/**
* Converts a view \a index to a map layer.
*/
QgsMapLayer *indexToLayer( const QModelIndex &index );
private:
QgsElevationProfileLayerTreeModel *mModel = nullptr;
QgsElevationProfileLayerTreeProxyModel *mProxyModel = nullptr;
QgsLayerTree *mLayerTree = nullptr;
};
#endif // QGSELEVATIONPROFILELAYERTREEVIEW_H

View File

@ -40,15 +40,21 @@
#include "qgsfillsymbollayer.h"
#include "qgsmarkersymbol.h"
#include "qgsmarkersymbollayer.h"
#include "qgslayertree.h"
#include "qgslayertreeregistrybridge.h"
#include "qgselevationprofilelayertreeview.h"
#include <QToolBar>
#include <QProgressBar>
#include <QTimer>
#include <QPrinter>
#include <QSplitter>
QgsElevationProfileWidget::QgsElevationProfileWidget( const QString &name )
: QWidget( nullptr )
, mCanvasName( name )
, mLayerTree( new QgsLayerTree() )
, mLayerTreeBridge( new QgsLayerTreeRegistryBridge( mLayerTree.get(), QgsProject::instance(), this ) )
{
setObjectName( QStringLiteral( "ElevationProfile" ) );
@ -58,6 +64,9 @@ QgsElevationProfileWidget::QgsElevationProfileWidget( const QString &name )
QToolBar *toolBar = new QToolBar( this );
toolBar->setIconSize( QgisApp::instance()->iconSize( true ) );
connect( mLayerTree.get(), &QgsLayerTree::layerOrderChanged, this, &QgsElevationProfileWidget::updateCanvasLayers );
connect( mLayerTree.get(), &QgsLayerTreeGroup::visibilityChanged, this, &QgsElevationProfileWidget::updateCanvasLayers );
mCanvas = new QgsElevationProfileCanvas( this );
mCanvas->setProject( QgsProject::instance() );
connect( mCanvas, &QgsElevationProfileCanvas::activeJobCountChanged, this, &QgsElevationProfileWidget::onTotalPendingJobsCountChanged );
@ -66,6 +75,16 @@ QgsElevationProfileWidget::QgsElevationProfileWidget( const QString &name )
mPanTool = new QgsPlotToolPan( mCanvas );
mCanvas->setTool( mPanTool );
mLayerTreeView = new QgsElevationProfileLayerTreeView( mLayerTree.get() );
connect( mLayerTreeView, &QAbstractItemView::doubleClicked, this, [ = ]( const QModelIndex & index )
{
if ( QgsMapLayer *layer = mLayerTreeView->indexToLayer( index ) )
{
QgisApp::instance()->showLayerProperties( layer, QStringLiteral( "mOptsPage_Elevation" ) );
}
} );
mZoomTool = new QgsPlotToolZoom( mCanvas );
mXAxisZoomTool = new QgsPlotToolXAxisZoom( mCanvas );
@ -187,15 +206,29 @@ QgsElevationProfileWidget::QgsElevationProfileWidget( const QString &name )
layout->setContentsMargins( 0, 0, 0, 0 );
layout->setSpacing( 0 );
layout->addLayout( topLayout );
layout->addWidget( mCanvas );
QSplitter *splitter = new QSplitter( Qt::Horizontal );
splitter->addWidget( mLayerTreeView ) ;
splitter->addWidget( mCanvas );
layout->addWidget( splitter );
splitter->setCollapsible( 0, false );
splitter->setCollapsible( 1, false );
splitter->setSizes( { QFontMetrics( font() ).horizontalAdvance( '0' ) * 10, splitter->width() } );
QgsSettings settings;
splitter->restoreState( settings.value( QStringLiteral( "Windows/ElevationProfile/SplitState" ) ).toByteArray() );
connect( splitter, &QSplitter::splitterMoved, this, [splitter]
{
QgsSettings settings;
settings.setValue( QStringLiteral( "Windows/ElevationProfile/SplitState" ), splitter->saveState() );
} );
setLayout( layout );
mDockableWidgetHelper = new QgsDockableWidgetHelper( true, mCanvasName, this, QgisApp::instance(), Qt::BottomDockWidgetArea, QStringList(), true );
QToolButton *toggleButton = mDockableWidgetHelper->createDockUndockToolButton();
toggleButton->setToolTip( tr( "Dock Elevation Profile View" ) );
toolBar->addWidget( toggleButton );
connect( mDockableWidgetHelper, &QgsDockableWidgetHelper::closed, [ = ]()
connect( mDockableWidgetHelper, &QgsDockableWidgetHelper::closed, this, [ = ]()
{
close();
} );
@ -205,6 +238,11 @@ QgsElevationProfileWidget::QgsElevationProfileWidget( const QString &name )
mSetCurveTimer->setSingleShot( true );
mSetCurveTimer->stop();
connect( mSetCurveTimer, &QTimer::timeout, this, &QgsElevationProfileWidget::updatePlot );
// initially populate layer tree with project layers
populateInitialLayers();
updateCanvasLayers();
}
QgsElevationProfileWidget::~QgsElevationProfileWidget()
@ -262,10 +300,6 @@ void QgsElevationProfileWidget::setMainCanvas( QgsMapCanvas *canvas )
mMapPointRubberBand->setSecondaryStrokeColor( QColor( 255, 255, 255, 100 ) );
mMapPointRubberBand->setColor( QColor( 0, 0, 0 ) );
mMapPointRubberBand->hide();
// only do this from map tool!
connect( mMainCanvas, &QgsMapCanvas::layersChanged, this, &QgsElevationProfileWidget::onMainCanvasLayersChanged );
onMainCanvasLayersChanged();
}
void QgsElevationProfileWidget::cancelJobs()
@ -273,16 +307,14 @@ void QgsElevationProfileWidget::cancelJobs()
mCanvas->cancelJobs();
}
void QgsElevationProfileWidget::onMainCanvasLayersChanged()
void QgsElevationProfileWidget::populateInitialLayers()
{
// possibly not right -- do we always want to sync the profile layers to canvas layers?
QList< QgsMapLayer * > layers = mMainCanvas->layers( true );
const QVector< QgsMapLayer * > layers = QgsProject::instance()->layers< QgsMapLayer * >();
// sort layers so that types which are more likely to obscure others are rendered below
// e.g. vector features should be drawn above raster DEMS, or the DEM line may completely obscure
// the vector feature
layers = QgsMapLayerUtils::sortLayersByType( layers,
QList< QgsMapLayer * > sortedLayers = QgsMapLayerUtils::sortLayersByType( QList< QgsMapLayer * >( layers.begin(), layers.end() ),
{
QgsMapLayerType::RasterLayer,
QgsMapLayerType::MeshLayer,
@ -290,6 +322,25 @@ void QgsElevationProfileWidget::onMainCanvasLayersChanged()
QgsMapLayerType::PointCloudLayer
} );
std::reverse( sortedLayers.begin(), sortedLayers.end() );
for ( QgsMapLayer *layer : std::as_const( sortedLayers ) )
{
mLayerTree->addLayer( layer );
}
}
void QgsElevationProfileWidget::updateCanvasLayers()
{
QList<QgsMapLayer *> layers;
const QList< QgsMapLayer * > layerOrder = mLayerTree->layerOrder();
layers.reserve( layerOrder.size() );
for ( QgsMapLayer *layer : layerOrder )
{
if ( mLayerTree->findLayer( layer )->isVisible() )
layers << layer;
}
std::reverse( layers.begin(), layers.end() );
mCanvas->setLayers( layers );
scheduleUpdate();
}

View File

@ -40,6 +40,9 @@ class QgsPlotToolZoom;
class QgsPlotToolXAxisZoom;
class QgsDoubleSpinBox;
class QgsElevationProfileWidgetSettingsAction;
class QgsElevationProfileLayerTreeView;
class QgsLayerTree;
class QgsLayerTreeRegistryBridge;
class QgsElevationProfileWidget : public QWidget
{
@ -67,7 +70,8 @@ class QgsElevationProfileWidget : public QWidget
void toggleDockModeRequested( bool docked );
private slots:
void onMainCanvasLayersChanged();
void populateInitialLayers();
void updateCanvasLayers();
void onTotalPendingJobsCountChanged( int count );
void setProfileCurve( const QgsGeometry &curve );
void onCanvasPointHovered( const QgsPointXY &point );
@ -106,6 +110,10 @@ class QgsElevationProfileWidget : public QWidget
QgsPlotToolZoom *mZoomTool = nullptr;
QgsElevationProfileWidgetSettingsAction *mSettingsAction = nullptr;
std::unique_ptr< QgsLayerTree > mLayerTree;
QgsLayerTreeRegistryBridge *mLayerTreeBridge = nullptr;
QgsElevationProfileLayerTreeView *mLayerTreeView = nullptr;
};

View File

@ -25,6 +25,7 @@ QgsMeshElevationPropertiesWidget::QgsMeshElevationPropertiesWidget( QgsMeshLayer
: QgsMapLayerConfigWidget( layer, canvas, parent )
{
setupUi( this );
setObjectName( QStringLiteral( "mOptsPage_Elevation" ) );
mOffsetZSpinBox->setClearValue( 0 );
mScaleZSpinBox->setClearValue( 1 );

View File

@ -25,6 +25,7 @@ QgsPointCloudElevationPropertiesWidget::QgsPointCloudElevationPropertiesWidget(
: QgsMapLayerConfigWidget( layer, canvas, parent )
{
setupUi( this );
setObjectName( QStringLiteral( "mOptsPage_Elevation" ) );
mOffsetZSpinBox->setClearValue( 0 );
mScaleZSpinBox->setClearValue( 1 );

View File

@ -25,6 +25,7 @@ QgsRasterElevationPropertiesWidget::QgsRasterElevationPropertiesWidget( QgsRaste
: QgsMapLayerConfigWidget( layer, canvas, parent )
{
setupUi( this );
setObjectName( QStringLiteral( "mOptsPage_Elevation" ) );
mOffsetZSpinBox->setClearValue( 0 );
mScaleZSpinBox->setClearValue( 1 );

View File

@ -28,6 +28,7 @@ QgsVectorElevationPropertiesWidget::QgsVectorElevationPropertiesWidget( QgsVecto
: QgsMapLayerConfigWidget( layer, canvas, parent )
{
setupUi( this );
setObjectName( QStringLiteral( "mOptsPage_Elevation" ) );
mOffsetZSpinBox->setClearValue( 0 );
mScaleZSpinBox->setClearValue( 1 );

View File

@ -370,6 +370,14 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel
void legendInvalidateMapBasedData();
protected:
/**
* Returns a temporary render context.
*
* \note Note available in Python bindings.
*/
QgsRenderContext *createTemporaryRenderContext() const SIP_SKIP;
//! Pointer to the root node of the layer tree. Not owned by the model
QgsLayerTree *mRootNode = nullptr;
//! Sets of flags for the model
@ -471,8 +479,6 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel
private:
//! Returns a temporary render context
QgsRenderContext *createTemporaryRenderContext() const;
};

View File

@ -353,8 +353,11 @@ void QgsVectorLayerProfileResults::renderResults( QgsProfileRenderContext &conte
continue;
markerSymbol->setColor( rendererSymbol->color() );
markerSymbol->setOpacity( rendererSymbol->opacity() );
lineSymbol->setColor( rendererSymbol->color() );
lineSymbol->setOpacity( rendererSymbol->opacity() );
fillSymbol->setColor( rendererSymbol->color() );
fillSymbol->setOpacity( rendererSymbol->opacity() );
markerSymbol->startRender( context.renderContext() );
lineSymbol->startRender( context.renderContext() );