Skip to content

Commit

Permalink
[FEATURE] add expressions at the symbollist level
Browse files Browse the repository at this point in the history
Size and Rotation can be defined by an expression for all symbols
composing a marker. Width can be defined by an expression for all
symbols composing a line.

For markers, a legend is generated for varying sizes. This allows
multivariate analysis legend in the case of classified/graduated colors.

The offset is now set along with size to maintain the relative position
of symbols composing a marker.

An asistant, with preview, is accessible through the data defined button
to help the user define the size expression. Three methods are
available: Frannery, Area and Radius.

Added a widget for use in categorized/classified symbology gui to set
the expression if needed. The assistant is also available from it.
  • Loading branch information
vmora authored and nyalldawson committed May 20, 2015
1 parent c38ff51 commit 1e46196
Show file tree
Hide file tree
Showing 25 changed files with 1,474 additions and 74 deletions.
1 change: 1 addition & 0 deletions python/gui/gui.sip
Expand Up @@ -172,6 +172,7 @@
%Include symbology-ng/characterwidget.sip
%Include symbology-ng/qgsdashspacedialog.sip
%Include symbology-ng/qgsdatadefinedsymboldialog.sip
%Include symbology-ng/qgssizescalewidget.sip
%Include symbology-ng/qgsstylev2exportimportdialog.sip
%Include symbology-ng/qgssvgselectorwidget.sip
%Include symbology-ng/qgsgraduatedhistogramwidget.sip
Expand Down
2 changes: 1 addition & 1 deletion python/gui/qgsdatadefinedbutton.sip
Expand Up @@ -11,7 +11,7 @@ class QgsDataDefinedAssistant: QDialog
#include <qgsdatadefinedbutton.h>
%End
public:
virtual QgsDataDefined* dataDefined() const = 0 /Factory/;
virtual QgsDataDefined dataDefined() const = 0;
};

/** \ingroup gui
Expand Down
11 changes: 11 additions & 0 deletions python/gui/symbology-ng/qgssizescalewidget.sip
@@ -0,0 +1,11 @@
class QgsSizeScaleWidget : QgsDataDefinedAssistant
{
%TypeHeaderCode
#include <qgssizescalewidget.h>
%End
public:
QgsSizeScaleWidget( const QgsVectorLayer * layer, const QgsMarkerSymbolV2 * symbol );

QgsDataDefined dataDefined() const;
};

2 changes: 1 addition & 1 deletion python/gui/symbology-ng/qgssymbolslistwidget.sip
Expand Up @@ -4,7 +4,7 @@ class QgsSymbolsListWidget : QWidget
#include <qgssymbolslistwidget.h>
%End
public:
QgsSymbolsListWidget( QgsSymbolV2* symbol, QgsStyleV2* style, QMenu* menu, QWidget* parent /TransferThis/ = 0 );
QgsSymbolsListWidget( QgsSymbolV2* symbol, QgsStyleV2* style, QMenu* menu, QWidget* parent /TransferThis/ = 0, const QgsVectorLayer * layer = 0 );

public slots:
void setSymbolFromStyle( const QModelIndex & index );
Expand Down
52 changes: 52 additions & 0 deletions src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp
Expand Up @@ -22,6 +22,8 @@
#include "qgspointdisplacementrenderer.h"
#include "qgsinvertedpolygonrenderer.h"
#include "qgspainteffect.h"
#include "qgsscaleexpression.h"
#include "qgsdatadefined.h"

#include "qgsfeature.h"
#include "qgsvectorlayer.h"
Expand Down Expand Up @@ -695,6 +697,56 @@ QgsLegendSymbolList QgsCategorizedSymbolRendererV2::legendSymbolItems( double sc
return lst;
}

QgsLegendSymbolListV2 QgsCategorizedSymbolRendererV2::legendSymbolItemsV2() const
{
QgsLegendSymbolListV2 lst;
if ( mSourceSymbol.data() && mSourceSymbol->type() == QgsSymbolV2::Marker )
{
// check that all symbols that have the same size expression
QgsDataDefined ddSize;
foreach ( QgsRendererCategoryV2 category, mCategories )
{
const QgsMarkerSymbolV2 * symbol = static_cast<const QgsMarkerSymbolV2 *>( category.symbol() );
if ( !ddSize.hasDefaultValues() && symbol->dataDefinedSize() != ddSize )
{
// no common size expression
return QgsFeatureRendererV2::legendSymbolItemsV2();
}
else
{
ddSize = symbol->dataDefinedSize();
}
}

if ( !ddSize.isActive() || !ddSize.useExpression() )
{
return QgsFeatureRendererV2::legendSymbolItemsV2();
}

QgsScaleExpression exp( ddSize.expressionString() );
if ( exp.type() != QgsScaleExpression::Unknown )
{
QgsLegendSymbolItemV2 title( NULL, exp.baseExpression(), "" );
lst << title;
foreach ( double v, QgsSymbolLayerV2Utils::prettyBreaks( exp.minValue(), exp.maxValue(), 4 ) )
{
QgsLegendSymbolItemV2 si( mSourceSymbol.data(), QString::number( v ), "" );
QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( si.symbol() );
s->setColor( QColor( 0, 0, 0 ) );
s->setDataDefinedSize( QgsDataDefined() );
s->setSize( exp.size( v ) );
lst << si;
}
// now list the categorized symbols
const QgsLegendSymbolListV2 list2 = QgsFeatureRendererV2::legendSymbolItemsV2() ;
foreach ( QgsLegendSymbolItemV2 item, list2 )
lst << item;
return lst;
}
}

return QgsFeatureRendererV2::legendSymbolItemsV2();
}

QgsSymbolV2* QgsCategorizedSymbolRendererV2::sourceSymbol()
{
Expand Down
3 changes: 3 additions & 0 deletions src/core/symbology-ng/qgscategorizedsymbolrendererv2.h
Expand Up @@ -139,6 +139,9 @@ class CORE_EXPORT QgsCategorizedSymbolRendererV2 : public QgsFeatureRendererV2
//! @note not available in python bindings
virtual QgsLegendSymbolList legendSymbolItems( double scaleDenominator = -1, QString rule = QString() ) override;

//! @note added in 2.10
QgsLegendSymbolListV2 legendSymbolItemsV2() const override;

QgsSymbolV2* sourceSymbol();
void setSourceSymbol( QgsSymbolV2* sym );

Expand Down
53 changes: 53 additions & 0 deletions src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp
Expand Up @@ -21,6 +21,8 @@
#include "qgspointdisplacementrenderer.h"
#include "qgsinvertedpolygonrenderer.h"
#include "qgspainteffect.h"
#include "qgsscaleexpression.h"
#include "qgsdatadefined.h"

#include "qgsfeature.h"
#include "qgsvectorlayer.h"
Expand Down Expand Up @@ -1151,6 +1153,57 @@ QgsLegendSymbologyList QgsGraduatedSymbolRendererV2::legendSymbologyItems( QSize
return lst;
}

QgsLegendSymbolListV2 QgsGraduatedSymbolRendererV2::legendSymbolItemsV2() const
{
QgsLegendSymbolListV2 list;
if ( mSourceSymbol.data() && mSourceSymbol->type() == QgsSymbolV2::Marker )
{
// check that all symbols that have the same size expression
QgsDataDefined ddSize;
foreach ( QgsRendererRangeV2 range, mRanges )
{
const QgsMarkerSymbolV2 * symbol = static_cast<const QgsMarkerSymbolV2 *>( range.symbol() );
if ( !ddSize.hasDefaultValues() && symbol->dataDefinedSize() != ddSize )
{
// no common size expression
return QgsFeatureRendererV2::legendSymbolItemsV2();
}
else
{
ddSize = symbol->dataDefinedSize();
}
}

if ( !ddSize.isActive() || !ddSize.useExpression() )
{
return QgsFeatureRendererV2::legendSymbolItemsV2();
}

QgsScaleExpression exp( ddSize.expressionString() );
if ( exp.type() != QgsScaleExpression::Unknown )
{
QgsLegendSymbolItemV2 title( NULL, exp.baseExpression(), "" );
list << title;
foreach ( double v, QgsSymbolLayerV2Utils::prettyBreaks( exp.minValue(), exp.maxValue(), 4 ) )
{
QgsLegendSymbolItemV2 si( mSourceSymbol.data(), QString::number( v ), "" );
QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( si.symbol() );
s->setColor( QColor( 0, 0, 0 ) );
s->setDataDefinedSize( QgsDataDefined() );
s->setSize( exp.size( v ) );
list << si;
}
// now list the graduated symbols
const QgsLegendSymbolListV2 list2 = QgsFeatureRendererV2::legendSymbolItemsV2() ;
foreach ( QgsLegendSymbolItemV2 item, list2 )
list << item;
return list;
}
}

return QgsFeatureRendererV2::legendSymbolItemsV2();
}

QgsLegendSymbolList QgsGraduatedSymbolRendererV2::legendSymbolItems( double scaleDenominator, QString rule )
{
Q_UNUSED( scaleDenominator );
Expand Down
4 changes: 4 additions & 0 deletions src/core/symbology-ng/qgsgraduatedsymbolrendererv2.h
Expand Up @@ -239,6 +239,10 @@ class CORE_EXPORT QgsGraduatedSymbolRendererV2 : public QgsFeatureRendererV2
//! @note not available in python bindings
virtual QgsLegendSymbolList legendSymbolItems( double scaleDenominator = -1, QString rule = QString() ) override;

//! @note added in 2.10
QgsLegendSymbolListV2 legendSymbolItemsV2() const override;


QgsSymbolV2* sourceSymbol();
void setSourceSymbol( QgsSymbolV2* sym );

Expand Down
26 changes: 26 additions & 0 deletions src/core/symbology-ng/qgssinglesymbolrendererv2.cpp
Expand Up @@ -26,6 +26,8 @@
#include "qgspointdisplacementrenderer.h"
#include "qgsinvertedpolygonrenderer.h"
#include "qgspainteffect.h"
#include "qgsscaleexpression.h"
#include "qgsdatadefined.h"

#include <QDomDocument>
#include <QDomElement>
Expand Down Expand Up @@ -384,6 +386,30 @@ QgsLegendSymbolList QgsSingleSymbolRendererV2::legendSymbolItems( double scaleDe
QgsLegendSymbolListV2 QgsSingleSymbolRendererV2::legendSymbolItemsV2() const
{
QgsLegendSymbolListV2 lst;
if ( mSymbol->type() == QgsSymbolV2::Marker )
{
const QgsMarkerSymbolV2 * symbol = static_cast<const QgsMarkerSymbolV2 *>( mSymbol.data() );
QgsDataDefined sizeDD = symbol->dataDefinedSize();
if ( sizeDD.isActive() && sizeDD.useExpression() )
{
QgsScaleExpression scaleExp( sizeDD.expressionString() );
if ( scaleExp.type() != QgsScaleExpression::Unknown )
{
QgsLegendSymbolItemV2 title( NULL, scaleExp.baseExpression(), 0 );
lst << title;
foreach ( double v, QgsSymbolLayerV2Utils::prettyBreaks( scaleExp.minValue(), scaleExp.maxValue(), 4 ) )
{
QgsLegendSymbolItemV2 si( mSymbol.data(), QString::number( v ), 0 );
QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( si.symbol() );
s->setDataDefinedSize( 0 );
s->setSize( scaleExp.size( v ) );
lst << si;
}
return lst;
}
}
}

lst << QgsLegendSymbolItemV2( mSymbol.data(), QString(), 0 );
return lst;
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/symbology-ng/qgssymbollayerv2.h
Expand Up @@ -21,7 +21,7 @@
#endif

#define DEG2RAD(x) ((x)*M_PI/180)
#define DEFAULT_SCALE_METHOD QgsSymbolV2::ScaleArea
#define DEFAULT_SCALE_METHOD QgsSymbolV2::ScaleDiameter

#include <QColor>
#include <QMap>
Expand Down Expand Up @@ -330,7 +330,7 @@ class CORE_EXPORT QgsMarkerSymbolLayerV2 : public QgsSymbolLayerV2
QgsSymbolV2::ScaleMethod scaleMethod() const { return mScaleMethod; }

void setOffset( QPointF offset ) { mOffset = offset; }
QPointF offset() { return mOffset; }
QPointF offset() const { return mOffset; }

virtual void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const override;

Expand Down

0 comments on commit 1e46196

Please sign in to comment.