Skip to content

Commit 8d72f13

Browse files
committed
[25d] Improve convertability to other layers
* Move height and angle expressions for 2.5D renderer to layer * Apply color based on main symbol color This makes the transition to other renderers easy. Fixes #14132
1 parent aca4999 commit 8d72f13

25 files changed

+287
-97
lines changed

python/core/qgsexpressioncontext.sip

+12
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,8 @@ class QgsExpressionContext
391391
static const QString EXPR_FIELDS;
392392
static const QString EXPR_FEATURE;
393393
static const QString EXPR_ORIGINAL_VALUE;
394+
static const QString EXPR_SYMBOL_COLOR;
395+
static const QString EXPR_SYMBOL_ANGLE;
394396
};
395397

396398
/** \ingroup core
@@ -488,6 +490,16 @@ class QgsExpressionContextUtils
488490
*/
489491
static QgsExpressionContextScope* mapSettingsScope( const QgsMapSettings &mapSettings ) /Factory/;
490492

493+
/**
494+
* Updates a symbol scope related to a QgsSymbolV2 to an expression context. If there is no existing scope
495+
* provided, a new one will be generated and returned.
496+
* @param symbol symbol to extract properties from
497+
* @param symbolScope optional pointer to an existing scope to update
498+
* @note added in QGIS 2.14
499+
*/
500+
static QgsExpressionContextScope* updateSymbolScope( const QgsSymbolV2* symbol, QgsExpressionContextScope* symbolScope = nullptr ) /Factory/;
501+
502+
491503
/** Creates a new scope which contains variables and functions relating to a QgsComposition.
492504
* For instance, number of pages and page sizes.
493505
* @param composition source composition

python/core/symbology-ng/qgs25drenderer.sip

+10-18
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,6 @@ class Qgs25DRenderer : QgsFeatureRendererV2
3939
virtual QgsSymbolV2* symbolForFeature( QgsFeature& feature, QgsRenderContext& context );
4040
virtual QgsSymbolV2List symbols( QgsRenderContext& context );
4141

42-
/**
43-
* Get the field or expression used to determine the height of extrusion
44-
*/
45-
QgsDataDefined height() const;
46-
/**
47-
* Set the field or expression used to determine the height of extrusion
48-
*/
49-
void setHeight( const QgsDataDefined& height );
50-
51-
/**
52-
* Get the angle for the extrusion effect
53-
*/
54-
int angle() const;
55-
/**
56-
* Set the angle for the extrusion effect
57-
*/
58-
void setAngle( int angle );
59-
6042
/**
6143
* Get the roof color
6244
*/
@@ -77,6 +59,16 @@ class Qgs25DRenderer : QgsFeatureRendererV2
7759
*/
7860
void setWallColor( const QColor& wallColor );
7961

62+
/**
63+
* Set wall shading enabled
64+
*/
65+
void setWallShadingEnabled( bool enabled );
66+
67+
/**
68+
* Get wall shading enabled
69+
*/
70+
bool wallShadingEnabled();
71+
8072
/**
8173
* Get the shadow's color
8274
*/

python/gui/symbology-ng/qgs25drendererwidget.sip

+4
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,8 @@ class Qgs25DRendererWidget : QgsRendererV2Widget
3535
Qgs25DRendererWidget( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer );
3636

3737
QgsFeatureRendererV2* renderer();
38+
39+
private:
40+
void apply();
41+
3842
};

python/gui/symbology-ng/qgsrendererv2propertiesdialog.sip

+8
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ class QgsRendererV2PropertiesDialog : QDialog
1515
*/
1616
void setMapCanvas( QgsMapCanvas* canvas );
1717

18+
signals:
19+
/**
20+
* Emitted when expression context variables on the associated
21+
* vector layers have been changed. Will request the parent dialog
22+
* to re-synchronize with the variables.
23+
*/
24+
void layerVariablesChanged();
25+
1826
public slots:
1927
//! called when user changes renderer type
2028
void rendererChanged();

python/gui/symbology-ng/qgsrendererv2widget.sip

+20
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,19 @@ class QgsRendererV2Widget : QWidget
3434
*/
3535
const QgsVectorLayer* vectorLayer() const;
3636

37+
/**
38+
* This method should be called whenever the renderer is actually set on the layer.
39+
*/
40+
void applyChanges();
41+
42+
signals:
43+
/**
44+
* Emitted when expression context variables on the associated
45+
* vector layers have been changed. Will request the parent dialog
46+
* to re-synchronize with the variables.
47+
*/
48+
void layerVariablesChanged();
49+
3750
protected:
3851
/** Subclasses may provide the capability of changing multiple symbols at once by implementing the following two methods
3952
and by connecting the slot contextMenuViewCategories(const QPoint&)*/
@@ -58,6 +71,13 @@ class QgsRendererV2Widget : QWidget
5871
virtual void copy();
5972
virtual void paste();
6073

74+
private:
75+
/**
76+
* This will be called whenever the renderer is set on a layer.
77+
* This can be overwritten in subclasses.
78+
*/
79+
virtual void apply();
80+
6181
};
6282

6383

src/app/qgslabelinggui.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,11 @@ static QgsExpressionContext _getExpressionContext( const void* context )
5050
if ( layer )
5151
expContext << QgsExpressionContextUtils::layerScope( layer );
5252

53+
expContext << QgsExpressionContextUtils::updateSymbolScope( nullptr );
54+
5355
//TODO - show actual value
5456
expContext.setOriginalValueVariable( QVariant() );
55-
expContext.setHighlightedVariables( QStringList() << QgsExpressionContext::EXPR_ORIGINAL_VALUE );
57+
expContext.setHighlightedVariables( QStringList() << QgsExpressionContext::EXPR_ORIGINAL_VALUE << QgsExpressionContext::EXPR_SYMBOL_COLOR );
5658

5759
return expContext;
5860
}

src/app/qgsvectorlayerproperties.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -1263,10 +1263,12 @@ void QgsVectorLayerProperties::updateSymbologyPage()
12631263
mRendererDialog = new QgsRendererV2PropertiesDialog( layer, QgsStyleV2::defaultStyle(), true );
12641264
mRendererDialog->setMapCanvas( QgisApp::instance()->mapCanvas() );
12651265

1266+
connect( mRendererDialog, SIGNAL( layerVariablesChanged() ), this, SLOT( updateVariableEditor() ) );
1267+
12661268
// display the menu to choose the output format (fix #5136)
12671269
mActionSaveStyleAs->setText( tr( "Save Style" ) );
12681270
mActionSaveStyleAs->setMenu( mSaveAsMenu );
1269-
QObject::disconnect( mActionSaveStyleAs, SIGNAL( triggered() ), this, SLOT( saveStyleAs_clicked() ) );
1271+
disconnect( mActionSaveStyleAs, SIGNAL( triggered() ), this, SLOT( saveStyleAs_clicked() ) );
12701272
}
12711273
else
12721274
{

src/core/qgsexpression.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -4546,6 +4546,9 @@ void QgsExpression::initVariableHelp()
45464546
//symbol variables
45474547
gVariableHelpTexts.insert( "geometry_part_count", QCoreApplication::translate( "variable_help", "Number of parts in rendered feature's geometry." ) );
45484548
gVariableHelpTexts.insert( "geometry_part_num", QCoreApplication::translate( "variable_help", "Current geometry part number for feature being rendered." ) );
4549+
4550+
gVariableHelpTexts.insert( "symbol_color", QCoreApplication::translate( "symbol_color", "Color of symbol used to render the feature." ) );
4551+
gVariableHelpTexts.insert( "symbol_angle", QCoreApplication::translate( "symbol_angle", "Angle of symbol used to render the feature (valid for marker symbols only)." ) );
45494552
}
45504553

45514554
QString QgsExpression::variableHelpText( const QString &variableName, bool showValue, const QVariant &value )

src/core/qgsexpressioncontext.cpp

+20
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
const QString QgsExpressionContext::EXPR_FIELDS( "_fields_" );
3434
const QString QgsExpressionContext::EXPR_FEATURE( "_feature_" );
3535
const QString QgsExpressionContext::EXPR_ORIGINAL_VALUE( "value" );
36+
const QString QgsExpressionContext::EXPR_SYMBOL_COLOR( "symbol_color" );
37+
const QString QgsExpressionContext::EXPR_SYMBOL_ANGLE( "symbol_angle" );
3638

3739
//
3840
// QgsExpressionContextScope
@@ -716,6 +718,24 @@ QgsExpressionContextScope* QgsExpressionContextUtils::mapSettingsScope( const Qg
716718
return scope;
717719
}
718720

721+
QgsExpressionContextScope* QgsExpressionContextUtils::updateSymbolScope( const QgsSymbolV2* symbol, QgsExpressionContextScope* symbolScope )
722+
{
723+
if ( !symbolScope )
724+
symbolScope = new QgsExpressionContextScope( QObject::tr( "Symbol Scope" ) );
725+
726+
symbolScope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_SYMBOL_COLOR, symbol ? symbol->color() : QColor(), true ) );
727+
728+
double angle = 0.0;
729+
const QgsMarkerSymbolV2* markerSymbol = dynamic_cast< const QgsMarkerSymbolV2* >( symbol );
730+
if ( markerSymbol )
731+
{
732+
angle = markerSymbol->angle();
733+
}
734+
symbolScope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_SYMBOL_ANGLE, angle, true ) );
735+
736+
return symbolScope;
737+
}
738+
719739
QgsExpressionContextScope *QgsExpressionContextUtils::compositionScope( const QgsComposition *composition )
720740
{
721741
QgsExpressionContextScope* scope = new QgsExpressionContextScope( QObject::tr( "Composition" ) );

src/core/qgsexpressioncontext.h

+13
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class QgsComposition;
2828
class QgsComposerItem;
2929
class QgsAtlasComposition;
3030
class QgsMapSettings;
31+
class QgsSymbolV2;
3132

3233
/** \ingroup core
3334
* \class QgsScopedExpressionFunction
@@ -425,6 +426,8 @@ class CORE_EXPORT QgsExpressionContext
425426
static const QString EXPR_FIELDS;
426427
static const QString EXPR_FEATURE;
427428
static const QString EXPR_ORIGINAL_VALUE;
429+
static const QString EXPR_SYMBOL_COLOR;
430+
static const QString EXPR_SYMBOL_ANGLE;
428431

429432
private:
430433

@@ -519,6 +522,16 @@ class CORE_EXPORT QgsExpressionContextUtils
519522
*/
520523
static QgsExpressionContextScope* mapSettingsScope( const QgsMapSettings &mapSettings );
521524

525+
/**
526+
* Updates a symbol scope related to a QgsSymbolV2 to an expression context. If there is no existing scope
527+
* provided, a new one will be generated and returned.
528+
* @param symbol symbol to extract properties from
529+
* @param symbolScope optional pointer to an existing scope to update
530+
* @note added in QGIS 2.14
531+
*/
532+
static QgsExpressionContextScope* updateSymbolScope( const QgsSymbolV2* symbol, QgsExpressionContextScope* symbolScope = nullptr );
533+
534+
522535
/** Creates a new scope which contains variables and functions relating to a QgsComposition.
523536
* For instance, number of pages and page sizes.
524537
* @param composition source composition

src/core/qgsvectorlayerlabelprovider.cpp

+19-8
Original file line numberDiff line numberDiff line change
@@ -281,19 +281,33 @@ QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( QgsRenderCon
281281
request.setSubsetOfAttributes( attrNames, mFields );
282282
QgsFeatureIterator fit = mSource->getFeatures( request );
283283

284+
QgsExpressionContextScope* symbolScope = nullptr;
284285
QgsFeature fet;
285286
while ( fit.nextFeature( fet ) )
286287
{
287288
QScopedPointer<QgsGeometry> obstacleGeometry;
288-
if ( fet.constGeometry()->type() == QGis::Point )
289+
if ( mRenderer )
289290
{
290-
//point feature, use symbol bounds as obstacle
291-
obstacleGeometry.reset( getPointObstacleGeometry( fet, ctx, mRenderer ) );
291+
QgsSymbolV2List symbols = mRenderer->originalSymbolsForFeature( fet, ctx );
292+
if ( !symbols.isEmpty() && fet.constGeometry()->type() == QGis::Point )
293+
{
294+
//point feature, use symbol bounds as obstacle
295+
obstacleGeometry.reset( QgsVectorLayerLabelProvider::getPointObstacleGeometry( fet, ctx, symbols ) );
296+
}
297+
if ( !symbols.isEmpty() )
298+
{
299+
symbolScope = QgsExpressionContextUtils::updateSymbolScope( symbols.at( 0 ), symbolScope );
300+
if ( !ctx.expressionContext().scopes().contains( symbolScope ) )
301+
ctx.expressionContext().appendScope( symbolScope );
302+
}
292303
}
293304
ctx.expressionContext().setFeature( fet );
294305
registerFeature( fet, ctx, obstacleGeometry.data() );
295306
}
296307

308+
if ( ctx.expressionContext().lastScope() == symbolScope )
309+
ctx.expressionContext().popScope();
310+
297311
if ( mRenderer )
298312
mRenderer->stopRender( ctx );
299313

@@ -308,14 +322,11 @@ void QgsVectorLayerLabelProvider::registerFeature( QgsFeature& feature, QgsRende
308322
mLabels << label;
309323
}
310324

311-
QgsGeometry* QgsVectorLayerLabelProvider::getPointObstacleGeometry( QgsFeature& fet, QgsRenderContext& context, QgsFeatureRendererV2* renderer )
325+
QgsGeometry* QgsVectorLayerLabelProvider::getPointObstacleGeometry( QgsFeature& fet, QgsRenderContext& context, const QgsSymbolV2List& symbols )
312326
{
313-
if ( !fet.constGeometry() || fet.constGeometry()->isEmpty() || fet.constGeometry()->type() != QGis::Point || !renderer )
327+
if ( !fet.constGeometry() || fet.constGeometry()->isEmpty() || fet.constGeometry()->type() != QGis::Point )
314328
return nullptr;
315329

316-
//calculate bounds for symbols for feature
317-
QgsSymbolV2List symbols = renderer->originalSymbolsForFeature( fet, context );
318-
319330
bool isMultiPoint = fet.constGeometry()->geometry()->nCoordinates() > 1;
320331
QgsAbstractGeometryV2* obstacleGeom = nullptr;
321332
if ( isMultiPoint )

src/core/qgsvectorlayerlabelprovider.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
#define QGSVECTORLAYERLABELPROVIDER_H
1818

1919
#include "qgslabelingenginev2.h"
20+
#include "qgsrendererv2.h"
2021

2122
class QgsAbstractFeatureSource;
2223
class QgsFeatureRendererV2;
24+
class QgsSymbolV2;
2325

2426
/**
2527
* @brief The QgsVectorLayerLabelProvider class implements a label provider
@@ -80,10 +82,10 @@ class CORE_EXPORT QgsVectorLayerLabelProvider : public QgsAbstractLabelProvider
8082
* point, and ensures that labels will not overlap large or offset points.
8183
* @param fet point feature
8284
* @param context render context
83-
* @param renderer renderer used for layer, required to determine symbols rendered for point feature
85+
* @param symbols symbols rendered for point feature
8486
* @note added in QGIS 2.14
8587
*/
86-
static QgsGeometry* getPointObstacleGeometry( QgsFeature& fet, QgsRenderContext& context, QgsFeatureRendererV2* renderer );
88+
static QgsGeometry* getPointObstacleGeometry( QgsFeature& fet, QgsRenderContext& context, const QgsSymbolV2List& symbols );
8789

8890
protected:
8991
//! initialization method - called from constructors

src/core/qgsvectorlayerrenderer.cpp

+31-4
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,9 @@ void QgsVectorLayerRenderer::setGeometryCachePointer( QgsGeometryCache* cache )
286286

287287
void QgsVectorLayerRenderer::drawRendererV2( QgsFeatureIterator& fit )
288288
{
289+
QgsExpressionContextScope* symbolScope = QgsExpressionContextUtils::updateSymbolScope( nullptr );
290+
mContext.expressionContext().appendScope( symbolScope );
291+
289292
QgsFeature fet;
290293
while ( fit.nextFeature( fet ) )
291294
{
@@ -332,10 +335,18 @@ void QgsVectorLayerRenderer::drawRendererV2( QgsFeatureIterator& fit )
332335
if ( mContext.labelingEngineV2() )
333336
{
334337
QScopedPointer<QgsGeometry> obstacleGeometry;
335-
if ( fet.constGeometry()->type() == QGis::Point )
338+
QgsSymbolV2List symbols = mRendererV2->originalSymbolsForFeature( fet, mContext );
339+
340+
if ( !symbols.isEmpty() && fet.constGeometry()->type() == QGis::Point )
336341
{
337-
obstacleGeometry.reset( QgsVectorLayerLabelProvider::getPointObstacleGeometry( fet, mContext, mRendererV2 ) );
342+
obstacleGeometry.reset( QgsVectorLayerLabelProvider::getPointObstacleGeometry( fet, mContext, symbols ) );
338343
}
344+
345+
if ( !symbols.isEmpty() )
346+
{
347+
QgsExpressionContextUtils::updateSymbolScope( symbols.at( 0 ), symbolScope );
348+
}
349+
339350
if ( mLabelProvider )
340351
{
341352
mLabelProvider->registerFeature( fet, mContext, obstacleGeometry.data() );
@@ -355,6 +366,8 @@ void QgsVectorLayerRenderer::drawRendererV2( QgsFeatureIterator& fit )
355366
}
356367
}
357368

369+
mContext.expressionContext().popScope();
370+
358371
stopRendererV2( nullptr );
359372
}
360373

@@ -371,6 +384,9 @@ void QgsVectorLayerRenderer::drawRendererV2Levels( QgsFeatureIterator& fit )
371384
selRenderer->startRender( mContext, mFields );
372385
}
373386

387+
QgsExpressionContextScope* symbolScope = QgsExpressionContextUtils::updateSymbolScope( nullptr );
388+
mContext.expressionContext().appendScope( symbolScope );
389+
374390
// 1. fetch features
375391
QgsFeature fet;
376392
while ( fit.nextFeature( fet ) )
@@ -382,6 +398,7 @@ void QgsVectorLayerRenderer::drawRendererV2Levels( QgsFeatureIterator& fit )
382398
{
383399
qDebug( "rendering stop!" );
384400
stopRendererV2( selRenderer );
401+
mContext.expressionContext().popScope();
385402
return;
386403
}
387404

@@ -420,10 +437,18 @@ void QgsVectorLayerRenderer::drawRendererV2Levels( QgsFeatureIterator& fit )
420437
if ( mContext.labelingEngineV2() )
421438
{
422439
QScopedPointer<QgsGeometry> obstacleGeometry;
423-
if ( fet.constGeometry()->type() == QGis::Point )
440+
QgsSymbolV2List symbols = mRendererV2->originalSymbolsForFeature( fet, mContext );
441+
442+
if ( !symbols.isEmpty() && fet.constGeometry()->type() == QGis::Point )
424443
{
425-
obstacleGeometry.reset( QgsVectorLayerLabelProvider::getPointObstacleGeometry( fet, mContext, mRendererV2 ) );
444+
obstacleGeometry.reset( QgsVectorLayerLabelProvider::getPointObstacleGeometry( fet, mContext, symbols ) );
426445
}
446+
447+
if ( !symbols.isEmpty() )
448+
{
449+
QgsExpressionContextUtils::updateSymbolScope( symbols.at( 0 ), symbolScope );
450+
}
451+
427452
if ( mLabelProvider )
428453
{
429454
mLabelProvider->registerFeature( fet, mContext, obstacleGeometry.data() );
@@ -435,6 +460,8 @@ void QgsVectorLayerRenderer::drawRendererV2Levels( QgsFeatureIterator& fit )
435460
}
436461
}
437462

463+
mContext.expressionContext().popScope();
464+
438465
// find out the order
439466
QgsSymbolV2LevelOrder levels;
440467
QgsSymbolV2List symbols = mRendererV2->symbols( mContext );

0 commit comments

Comments
 (0)