38 changes: 38 additions & 0 deletions src/core/diagram/qgsdiagram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,33 @@
#include "qgsdiagram.h"
#include "qgsdiagramrendererv2.h"
#include "qgsrendercontext.h"
#include "qgsexpression.h"

#include <QPainter>


void QgsDiagram::clearCache()
{
QMapIterator<QString, QgsExpression*> i( mExpressions );
while ( i.hasNext() )
{
i.next();
delete i.value();
}
mExpressions.clear();
}

QgsExpression* QgsDiagram::getExpression( const QString& expression, const QgsFields* fields )
{
if ( !mExpressions.contains( expression ) )
{
QgsExpression* expr = new QgsExpression( expression );
expr->prepare( *fields );
mExpressions[expression] = expr;
}
return mExpressions[expression];
}

void QgsDiagram::setPenWidth( QPen& pen, const QgsDiagramSettings& s, const QgsRenderContext& c )
{
if ( s.sizeType == QgsDiagramSettings::MM )
Expand Down Expand Up @@ -69,3 +93,17 @@ QFont QgsDiagram::scaledFont( const QgsDiagramSettings& s, const QgsRenderContex

return f;
}

void QgsDiagram::renderDiagram( const QgsAttributes& attributes, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
{
QgsFeature feature;
feature.setAttributes( attributes );
renderDiagram( feature, c, s, position );
}

QSizeF QgsDiagram::diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is )
{
QgsFeature feature;
feature.setAttributes( attributes );
return diagramSize( feature, c, s, is );
}
17 changes: 14 additions & 3 deletions src/core/diagram/qgsdiagram.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,28 @@ class QgsDiagramInterpolationSettings;

class QgsRenderContext;

class QgsExpression;



/**Base class for all diagram types*/
class CORE_EXPORT QgsDiagram
{
public:
virtual ~QgsDiagram() {}
virtual ~QgsDiagram() { clearCache(); }
void clearCache();
QgsExpression* getExpression( const QString& expression, const QgsFields* fields );
/** @deprecated `void renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )` should be used instead */
virtual Q_DECL_DEPRECATED void renderDiagram( const QgsAttributes& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
/**Draws the diagram at the given position (in pixel coordinates)*/
virtual void renderDiagram( const QgsAttributes& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position ) = 0;
virtual void renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position ) = 0;
virtual QString diagramName() const = 0;
/**Returns the size in map units the diagram will use to render.*/
virtual QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s ) = 0;
/** @deprecated `QSizeF diagramSize( const QgsFeature& feature, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is )` should be used instead */
virtual Q_DECL_DEPRECATED QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is );
/**Returns the size in map units the diagram will use to render. Interpolate size*/
virtual QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is ) = 0;
virtual QSizeF diagramSize( const QgsFeature& feature, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is ) = 0;

protected:
/** Changes the pen width to match the current settings and rendering context
Expand Down Expand Up @@ -74,6 +82,9 @@ class CORE_EXPORT QgsDiagram
* @return The properly scaled font for rendering
*/
QFont scaledFont( const QgsDiagramSettings& s, const QgsRenderContext& c );

private:
QMap<QString, QgsExpression*> mExpressions;
};

#endif // QGSDIAGRAM_H
21 changes: 12 additions & 9 deletions src/core/diagram/qgshistogramdiagram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "qgshistogramdiagram.h"
#include "qgsdiagramrendererv2.h"
#include "qgsrendercontext.h"
#include "qgsexpression.h"

#include <QPainter>

Expand All @@ -29,20 +30,21 @@ QgsHistogramDiagram::~QgsHistogramDiagram()
{
}

QSizeF QgsHistogramDiagram::diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is )
QSizeF QgsHistogramDiagram::diagramSize( const QgsFeature& feature, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is )
{
Q_UNUSED( c );
QSizeF size;
if ( attributes.count() == 0 )
if ( feature.attributes().count() == 0 )
{
return size; //zero size if no attributes
}

double maxValue = 0;

foreach ( int cat, s.categoryIndices )
foreach ( QString cat, s.categoryAttributes )
{
maxValue = qMax( attributes[cat].toDouble(), maxValue );
QgsExpression* expression = getExpression( cat, feature.fields() );
maxValue = qMax( expression->evaluate( feature ).toDouble(), maxValue );
}

// Scale, if extension is smaller than the specified minimum
Expand All @@ -56,13 +58,13 @@ QSizeF QgsHistogramDiagram::diagramSize( const QgsAttributes& attributes, const
case QgsDiagramSettings::Up:
case QgsDiagramSettings::Down:
mScaleFactor = (( is.upperSize.width() - is.lowerSize.height() ) / ( is.upperValue - is.lowerValue ) );
size.scale( s.barWidth * s.categoryIndices.size(), maxValue * mScaleFactor, Qt::IgnoreAspectRatio );
size.scale( s.barWidth * s.categoryAttributes.size(), maxValue * mScaleFactor, Qt::IgnoreAspectRatio );
break;

case QgsDiagramSettings::Right:
case QgsDiagramSettings::Left:
mScaleFactor = (( is.upperSize.width() - is.lowerSize.width() ) / ( is.upperValue - is.lowerValue ) );
size.scale( maxValue * mScaleFactor, s.barWidth * s.categoryIndices.size(), Qt::IgnoreAspectRatio );
size.scale( maxValue * mScaleFactor, s.barWidth * s.categoryAttributes.size(), Qt::IgnoreAspectRatio );
break;
}

Expand Down Expand Up @@ -105,7 +107,7 @@ QSizeF QgsHistogramDiagram::diagramSize( const QgsAttributes& attributes, const
return size;
}

void QgsHistogramDiagram::renderDiagram( const QgsAttributes& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
void QgsHistogramDiagram::renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
{
QPainter* p = c.painter();
if ( !p )
Expand All @@ -116,9 +118,10 @@ void QgsHistogramDiagram::renderDiagram( const QgsAttributes& att, QgsRenderCont
QList<double> values;
double maxValue = 0;

foreach ( int cat, s.categoryIndices )
foreach ( QString cat, s.categoryAttributes )
{
double currentVal = att[cat].toDouble();
QgsExpression* expression = getExpression( cat, feature.fields() );
double currentVal = expression->evaluate( feature ).toDouble();
values.push_back( currentVal );
maxValue = qMax( currentVal, maxValue );
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/diagram/qgshistogramdiagram.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ class CORE_EXPORT QgsHistogramDiagram: public QgsDiagram
QgsHistogramDiagram();
~QgsHistogramDiagram();

void renderDiagram( const QgsAttributes& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
void renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s );
QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is );
QSizeF diagramSize( const QgsFeature& feature, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is );
QString diagramName() const { return DIAGRAM_NAME_HISTOGRAM; }

private:
Expand Down
25 changes: 19 additions & 6 deletions src/core/diagram/qgspiediagram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "qgspiediagram.h"
#include "qgsdiagramrendererv2.h"
#include "qgsrendercontext.h"
#include "qgsexpression.h"

#include <QPainter>

Expand All @@ -29,10 +30,21 @@ QgsPieDiagram::~QgsPieDiagram()
{
}

QSizeF QgsPieDiagram::diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is )
QSizeF QgsPieDiagram::diagramSize( const QgsFeature& feature, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is )
{
Q_UNUSED( c );
QVariant attrVal = attributes[is.classificationAttribute];

QVariant attrVal;
if ( is.classificationAttributeIsExpression )
{
QgsExpression* expression = getExpression( is.classificationAttributeExpression, feature.fields() );
attrVal = expression->evaluate( feature );
}
else
{
attrVal = feature.attributes()[is.classificationAttribute];
}

if ( !attrVal.isValid() )
{
return QSizeF(); //zero size if attribute is missing
Expand Down Expand Up @@ -90,7 +102,7 @@ QSizeF QgsPieDiagram::diagramSize( const QgsAttributes& attributes, const QgsRen

int QgsPieDiagram::sCount = 0;

void QgsPieDiagram::renderDiagram( const QgsAttributes& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
void QgsPieDiagram::renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
{
QPainter* p = c.painter();
if ( !p )
Expand All @@ -104,10 +116,11 @@ void QgsPieDiagram::renderDiagram( const QgsAttributes& att, QgsRenderContext& c
double valSum = 0;
int valCount = 0;

QList<int>::const_iterator catIt = s.categoryIndices.constBegin();
for ( ; catIt != s.categoryIndices.constEnd(); ++catIt )
QList<QString>::const_iterator catIt = s.categoryAttributes.constBegin();
for ( ; catIt != s.categoryAttributes.constEnd(); ++catIt )
{
currentVal = att[*catIt].toDouble();
QgsExpression* expression = getExpression( *catIt, feature.fields() );
currentVal = expression->evaluate( feature ).toDouble();
values.push_back( currentVal );
valSum += currentVal;
if ( currentVal ) valCount++;
Expand Down
4 changes: 2 additions & 2 deletions src/core/diagram/qgspiediagram.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ class CORE_EXPORT QgsPieDiagram: public QgsDiagram
QgsPieDiagram();
~QgsPieDiagram();

void renderDiagram( const QgsAttributes& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
void renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s );
QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is );
QSizeF diagramSize( const QgsFeature& feature, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is );
QString diagramName() const { return DIAGRAM_NAME_PIE; }

private:
Expand Down
24 changes: 19 additions & 5 deletions src/core/diagram/qgstextdiagram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "qgstextdiagram.h"
#include "qgsdiagramrendererv2.h"
#include "qgsrendercontext.h"
#include "qgsexpression.h"

#include <QPainter>

Expand All @@ -30,11 +31,20 @@ QgsTextDiagram::~QgsTextDiagram()
{
}

QSizeF QgsTextDiagram::diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is )
QSizeF QgsTextDiagram::diagramSize( const QgsFeature& feature, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is )
{
Q_UNUSED( c );

QVariant attrVal = attributes[is.classificationAttribute];
QVariant attrVal;
if ( is.classificationAttributeIsExpression )
{
QgsExpression* expression = getExpression( is.classificationAttributeExpression, feature.fields() );
attrVal = expression->evaluate( feature );
}
else
{
attrVal = feature.attributes()[is.classificationAttribute];
}

if ( !attrVal.isValid() )
{
Expand Down Expand Up @@ -84,8 +94,10 @@ QSizeF QgsTextDiagram::diagramSize( const QgsAttributes& attributes, const QgsRe
return s.size;
}

void QgsTextDiagram::renderDiagram( const QgsAttributes& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
void QgsTextDiagram::renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
{
Q_UNUSED( feature );

QPainter* p = c.painter();
if ( !p )
{
Expand All @@ -108,7 +120,7 @@ void QgsTextDiagram::renderDiagram( const QgsAttributes& att, QgsRenderContext&
double baseY = position.y() - h;

QList<QPointF> textPositions; //midpoints for text placement
int nCategories = s.categoryIndices.size();
int nCategories = s.categoryAttributes.size();
for ( int i = 0; i < nCategories; ++i )
{
if ( mOrientation == Horizontal )
Expand Down Expand Up @@ -210,7 +222,9 @@ void QgsTextDiagram::renderDiagram( const QgsAttributes& att, QgsRenderContext&

for ( int i = 0; i < textPositions.size(); ++i )
{
QString val = att[ s.categoryIndices.at( i )].toString();
QgsExpression* expression = getExpression( s.categoryAttributes.at( i ), feature.fields() );
QString val = expression->evaluate( feature ).toString();

//find out dimesions
double textWidth = fontMetrics.width( val );
double textHeight = fontMetrics.height();
Expand Down
4 changes: 2 additions & 2 deletions src/core/diagram/qgstextdiagram.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ class CORE_EXPORT QgsTextDiagram: public QgsDiagram

QgsTextDiagram();
~QgsTextDiagram();
void renderDiagram( const QgsAttributes& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
void renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s );
QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is );
QSizeF diagramSize( const QgsFeature& feature, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is );

QString diagramName() const { return DIAGRAM_NAME_TEXT; }

Expand Down
69 changes: 42 additions & 27 deletions src/core/qgsdiagramrendererv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ void QgsDiagramLayerSettings::writeXML( QDomElement& layerElem, QDomDocument& do

void QgsDiagramSettings::readXML( const QDomElement& elem, const QgsVectorLayer* layer )
{
Q_UNUSED( layer );

font.fromString( elem.attribute( "font" ) );
backgroundColor.setNamedColor( elem.attribute( "backgroundColor" ) );
backgroundColor.setAlpha( elem.attribute( "backgroundAlpha" ).toInt() );
Expand Down Expand Up @@ -132,7 +134,7 @@ void QgsDiagramSettings::readXML( const QDomElement& elem, const QgsVectorLayer*
QColor newColor( attrElem.attribute( "color" ) );
newColor.setAlpha( 255 - transparency );
categoryColors.append( newColor );
categoryIndices.append( layer->fieldNameIndex( attrElem.attribute( "field" ) ) );
categoryAttributes.append( attrElem.attribute( "field" ) );
}
}
else
Expand All @@ -149,18 +151,20 @@ void QgsDiagramSettings::readXML( const QDomElement& elem, const QgsVectorLayer*
}

//attribute indices
categoryIndices.clear();
categoryAttributes.clear();
QStringList catList = elem.attribute( "categories" ).split( "/" );
QStringList::const_iterator catIt = catList.constBegin();
for ( ; catIt != catList.constEnd(); ++catIt )
{
categoryIndices.append( catIt->toInt() );
categoryAttributes.append( *catIt );
}
}
}

void QgsDiagramSettings::writeXML( QDomElement& rendererElem, QDomDocument& doc, const QgsVectorLayer* layer ) const
{
Q_UNUSED( layer );

QDomElement categoryElem = doc.createElement( "DiagramCategory" );
categoryElem.setAttribute( "font", font.toString() );
categoryElem.setAttribute( "backgroundColor", backgroundColor.name() );
Expand Down Expand Up @@ -232,12 +236,12 @@ void QgsDiagramSettings::writeXML( QDomElement& rendererElem, QDomDocument& doc,
categoryElem.setAttribute( "angleOffset", QString::number( angleOffset ) );

QString colors;
int nCats = qMin( categoryColors.size(), categoryIndices.size() );
int nCats = qMin( categoryColors.size(), categoryAttributes.size() );
for ( int i = 0; i < nCats; ++i )
{
QDomElement attributeElem = doc.createElement( "attribute" );

attributeElem.setAttribute( "field", layer->pendingFields().at( categoryIndices.at( i ) ).name() );
attributeElem.setAttribute( "field", categoryAttributes.at( i ) );
attributeElem.setAttribute( "color", categoryColors.at( i ).name() );
categoryElem.appendChild( attributeElem );
}
Expand All @@ -260,31 +264,31 @@ void QgsDiagramRendererV2::setDiagram( QgsDiagram* d )
mDiagram = d;
}

void QgsDiagramRendererV2::renderDiagram( const QgsAttributes& att, QgsRenderContext& c, const QPointF& pos )
void QgsDiagramRendererV2::renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QPointF& pos )
{
if ( !mDiagram )
{
return;
}

QgsDiagramSettings s;
if ( !diagramSettings( att, c, s ) )
if ( !diagramSettings( feature, c, s ) )
{
return;
}

mDiagram->renderDiagram( att, c, s, pos );
mDiagram->renderDiagram( feature, c, s, pos );
}

QSizeF QgsDiagramRendererV2::sizeMapUnits( const QgsAttributes& attributes, const QgsRenderContext& c )
QSizeF QgsDiagramRendererV2::sizeMapUnits( const QgsFeature& feature, const QgsRenderContext& c )
{
QgsDiagramSettings s;
if ( !diagramSettings( attributes, c, s ) )
if ( !diagramSettings( feature, c, s ) )
{
return QSizeF();
}

QSizeF size = diagramSize( attributes, c );
QSizeF size = diagramSize( feature, c );
if ( s.sizeType == QgsDiagramSettings::MM )
{
convertSizeToMapUnits( size, c );
Expand Down Expand Up @@ -360,16 +364,16 @@ QgsSingleCategoryDiagramRenderer::~QgsSingleCategoryDiagramRenderer()
{
}

bool QgsSingleCategoryDiagramRenderer::diagramSettings( const QgsAttributes&, const QgsRenderContext& c, QgsDiagramSettings& s )
bool QgsSingleCategoryDiagramRenderer::diagramSettings( const QgsFeature&, const QgsRenderContext& c, QgsDiagramSettings& s )
{
Q_UNUSED( c );
s = mSettings;
return true;
}

QSizeF QgsSingleCategoryDiagramRenderer::diagramSize( const QgsAttributes &attributes, const QgsRenderContext &c )
QSizeF QgsSingleCategoryDiagramRenderer::diagramSize( const QgsFeature &feature, const QgsRenderContext &c )
{
return mDiagram->diagramSize( attributes, c, mSettings );
return mDiagram->diagramSize( feature.attributes(), c, mSettings );
}

QList<QgsDiagramSettings> QgsSingleCategoryDiagramRenderer::diagramSettings() const
Expand Down Expand Up @@ -402,6 +406,7 @@ void QgsSingleCategoryDiagramRenderer::writeXML( QDomElement& layerElem, QDomDoc

QgsLinearlyInterpolatedDiagramRenderer::QgsLinearlyInterpolatedDiagramRenderer(): QgsDiagramRendererV2()
{
mInterpolationSettings.classificationAttributeIsExpression = false;
}

QgsLinearlyInterpolatedDiagramRenderer::~QgsLinearlyInterpolatedDiagramRenderer()
Expand All @@ -415,26 +420,21 @@ QList<QgsDiagramSettings> QgsLinearlyInterpolatedDiagramRenderer::diagramSetting
return settingsList;
}

bool QgsLinearlyInterpolatedDiagramRenderer::diagramSettings( const QgsAttributes& attributes, const QgsRenderContext& c, QgsDiagramSettings& s )
bool QgsLinearlyInterpolatedDiagramRenderer::diagramSettings( const QgsFeature& feature, const QgsRenderContext& c, QgsDiagramSettings& s )
{
s = mSettings;
s.size = diagramSize( attributes, c );
s.size = diagramSize( feature, c );
return true;
}

QList<int> QgsLinearlyInterpolatedDiagramRenderer::diagramAttributes() const
QList<QString> QgsLinearlyInterpolatedDiagramRenderer::diagramAttributes() const
{
QList<int> attributes = mSettings.categoryIndices;
if ( !attributes.contains( mInterpolationSettings.classificationAttribute ) )
{
attributes.push_back( mInterpolationSettings.classificationAttribute );
}
return attributes;
return mSettings.categoryAttributes;
}

QSizeF QgsLinearlyInterpolatedDiagramRenderer::diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c )
QSizeF QgsLinearlyInterpolatedDiagramRenderer::diagramSize( const QgsFeature& feature, const QgsRenderContext& c )
{
return mDiagram->diagramSize( attributes, c, mSettings, mInterpolationSettings );
return mDiagram->diagramSize( feature, c, mSettings, mInterpolationSettings );
}

void QgsLinearlyInterpolatedDiagramRenderer::readXML( const QDomElement& elem, const QgsVectorLayer* layer )
Expand All @@ -445,7 +445,15 @@ void QgsLinearlyInterpolatedDiagramRenderer::readXML( const QDomElement& elem, c
mInterpolationSettings.lowerSize.setHeight( elem.attribute( "lowerHeight" ).toDouble() );
mInterpolationSettings.upperSize.setWidth( elem.attribute( "upperWidth" ).toDouble() );
mInterpolationSettings.upperSize.setHeight( elem.attribute( "upperHeight" ).toDouble() );
mInterpolationSettings.classificationAttribute = elem.attribute( "classificationAttribute" ).toInt();
mInterpolationSettings.classificationAttributeIsExpression = elem.hasAttribute( "classificationAttributeExpression" );
if ( mInterpolationSettings.classificationAttributeIsExpression )
{
mInterpolationSettings.classificationAttributeExpression = elem.attribute( "classificationAttributeExpression" );
}
else
{
mInterpolationSettings.classificationAttribute = elem.attribute( "classificationAttribute" ).toInt();
}
QDomElement settingsElem = elem.firstChildElement( "DiagramCategory" );
if ( !settingsElem.isNull() )
{
Expand All @@ -463,7 +471,14 @@ void QgsLinearlyInterpolatedDiagramRenderer::writeXML( QDomElement& layerElem, Q
rendererElem.setAttribute( "lowerHeight", QString::number( mInterpolationSettings.lowerSize.height() ) );
rendererElem.setAttribute( "upperWidth", QString::number( mInterpolationSettings.upperSize.width() ) );
rendererElem.setAttribute( "upperHeight", QString::number( mInterpolationSettings.upperSize.height() ) );
rendererElem.setAttribute( "classificationAttribute", mInterpolationSettings.classificationAttribute );
if ( mInterpolationSettings.classificationAttributeIsExpression )
{
rendererElem.setAttribute( "classificationAttributeExpression", mInterpolationSettings.classificationAttributeExpression );
}
else
{
rendererElem.setAttribute( "classificationAttribute", mInterpolationSettings.classificationAttribute );
}
mSettings.writeXML( rendererElem, doc, layer );
_writeXML( rendererElem, doc, layer );
layerElem.appendChild( rendererElem );
Expand Down
38 changes: 23 additions & 15 deletions src/core/qgsdiagramrendererv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class CORE_EXPORT QgsDiagramSettings
{}
QFont font;
QList< QColor > categoryColors;
QList< int > categoryIndices;
QList< QString > categoryAttributes;
QSizeF size; //size
SizeType sizeType; //mm or map units
QColor backgroundColor;
Expand Down Expand Up @@ -157,6 +157,8 @@ class CORE_EXPORT QgsDiagramInterpolationSettings
double upperValue;
/**Index of the classification attribute*/
int classificationAttribute;
QString classificationAttributeExpression;
bool classificationAttributeIsExpression;
};

/**Returns diagram settings for a feature*/
Expand All @@ -167,18 +169,18 @@ class CORE_EXPORT QgsDiagramRendererV2
QgsDiagramRendererV2();
virtual ~QgsDiagramRendererV2();

/**Returns size of the diagram for feature f in map units. Returns an invalid QSizeF in case of error*/
virtual QSizeF sizeMapUnits( const QgsAttributes& attributes, const QgsRenderContext& c );
/**Returns size of the diagram for a feature in map units. Returns an invalid QSizeF in case of error*/
virtual QSizeF sizeMapUnits( const QgsFeature& feature, const QgsRenderContext& c );

virtual QString rendererName() const = 0;

/**Returns attribute indices needed for diagram rendering*/
virtual QList<int> diagramAttributes() const = 0;
virtual QList<QString> diagramAttributes() const = 0;

void renderDiagram( const QgsAttributes& att, QgsRenderContext& c, const QPointF& pos );
void renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QPointF& pos );

void setDiagram( QgsDiagram* d );
const QgsDiagram* diagram() const { return mDiagram; }
QgsDiagram* diagram() const { return mDiagram; }

/**Returns list with all diagram settings in the renderer*/
virtual QList<QgsDiagramSettings> diagramSettings() const = 0;
Expand All @@ -189,14 +191,14 @@ class CORE_EXPORT QgsDiagramRendererV2
protected:

/**Returns diagram settings for a feature (or false if the diagram for the feature is not to be rendered). Used internally within renderDiagram()
* @param att attribute map
* @param feature the feature
* @param c render context
* @param s out: diagram settings for the feature
*/
virtual bool diagramSettings( const QgsAttributes& att, const QgsRenderContext& c, QgsDiagramSettings& s ) = 0;
virtual bool diagramSettings( const QgsFeature&, const QgsRenderContext& c, QgsDiagramSettings& s ) = 0;

/**Returns size of the diagram (in painter units) or an invalid size in case of error*/
virtual QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c ) = 0;
virtual QSizeF diagramSize( const QgsFeature& features, const QgsRenderContext& c ) = 0;

/**Converts size from mm to map units*/
void convertSizeToMapUnits( QSizeF& size, const QgsRenderContext& context ) const;
Expand All @@ -221,7 +223,7 @@ class CORE_EXPORT QgsSingleCategoryDiagramRenderer : public QgsDiagramRendererV2

QString rendererName() const { return "SingleCategory"; }

QList<int> diagramAttributes() const { return mSettings.categoryIndices; }
QList<QString> diagramAttributes() const { return mSettings.categoryAttributes; }

void setDiagramSettings( const QgsDiagramSettings& s ) { mSettings = s; }

Expand All @@ -231,9 +233,9 @@ class CORE_EXPORT QgsSingleCategoryDiagramRenderer : public QgsDiagramRendererV2
void writeXML( QDomElement& layerElem, QDomDocument& doc, const QgsVectorLayer* layer ) const;

protected:
bool diagramSettings( const QgsAttributes&, const QgsRenderContext& c, QgsDiagramSettings& s );
bool diagramSettings( const QgsFeature&, const QgsRenderContext& c, QgsDiagramSettings& s );

QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c );
QSizeF diagramSize( const QgsFeature&, const QgsRenderContext& c );

private:
QgsDiagramSettings mSettings;
Expand All @@ -250,7 +252,7 @@ class CORE_EXPORT QgsLinearlyInterpolatedDiagramRenderer : public QgsDiagramRend

void setDiagramSettings( const QgsDiagramSettings& s ) { mSettings = s; }

QList<int> diagramAttributes() const;
QList<QString> diagramAttributes() const;

QString rendererName() const { return "LinearlyInterpolated"; }

Expand All @@ -269,13 +271,19 @@ class CORE_EXPORT QgsLinearlyInterpolatedDiagramRenderer : public QgsDiagramRend
int classificationAttribute() const { return mInterpolationSettings.classificationAttribute; }
void setClassificationAttribute( int index ) { mInterpolationSettings.classificationAttribute = index; }

QString classificationAttributeExpression() const { return mInterpolationSettings.classificationAttributeExpression; }
void setClassificationAttributeExpression( QString expression ) { mInterpolationSettings.classificationAttributeExpression = expression; }

bool classificationAttributeIsExpression() const { return mInterpolationSettings.classificationAttributeIsExpression; }
void setClassificationAttributeIsExpression( bool isExpression ) { mInterpolationSettings.classificationAttributeIsExpression = isExpression; }

void readXML( const QDomElement& elem, const QgsVectorLayer* layer );
void writeXML( QDomElement& layerElem, QDomDocument& doc, const QgsVectorLayer* layer ) const;

protected:
bool diagramSettings( const QgsAttributes&, const QgsRenderContext& c, QgsDiagramSettings& s );
bool diagramSettings( const QgsFeature&, const QgsRenderContext& c, QgsDiagramSettings& s );

QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c );
QSizeF diagramSize( const QgsFeature&, const QgsRenderContext& c );

private:
QgsDiagramSettings mSettings;
Expand Down
21 changes: 16 additions & 5 deletions src/core/qgspallabeling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class QgsPalGeometry : public PalGeometry
, mWordSpacing( wordSpacing )
, mCurvedLabeling( curvedLabeling )
{
mStrId = FID_TO_STRING( id ).toAscii();
mStrId = FID_TO_STRING( mId ).toAscii();
mDefinedFont = QFont();
}

Expand Down Expand Up @@ -172,9 +172,17 @@ class QgsPalGeometry : public PalGeometry

QFontMetricsF* getLabelFontMetrics() { return mFontMetrics; }

void setDiagramAttributes( const QgsAttributes& attrs ) { mDiagramAttributes = attrs; }
void setDiagramAttributes( const QgsAttributes& attrs, const QgsFields* fields ) { mDiagramAttributes = attrs; mDiagramFields = fields; }
const QgsAttributes& diagramAttributes() { return mDiagramAttributes; }

void feature( QgsFeature& feature )
{
feature.setFeatureId( mId );
feature.setFields( mDiagramFields, false );
feature.setAttributes( mDiagramAttributes );
feature.setValid( true );
}

protected:
GEOSGeometry* mG;
QString mText;
Expand All @@ -193,6 +201,7 @@ class QgsPalGeometry : public PalGeometry

/**Stores attribute values for diagram rendering*/
QgsAttributes mDiagramAttributes;
const QgsFields* mDiagramFields;
};

// -------------
Expand Down Expand Up @@ -3357,15 +3366,15 @@ void QgsPalLabeling::registerDiagramFeature( QgsVectorLayer* layer, QgsFeature&
QgsDiagramRendererV2* dr = layerIt.value().renderer;
if ( dr )
{
QSizeF diagSize = dr->sizeMapUnits( feat.attributes(), context );
QSizeF diagSize = dr->sizeMapUnits( feat, context );
if ( diagSize.isValid() )
{
diagramWidth = diagSize.width();
diagramHeight = diagSize.height();
}

//append the diagram attributes to lbl
lbl->setDiagramAttributes( feat.attributes() );
lbl->setDiagramAttributes( feat.attributes(), feat.fields() );
}

// feature to the layer
Expand Down Expand Up @@ -3866,14 +3875,16 @@ void QgsPalLabeling::drawLabeling( QgsRenderContext& context )
QString layerName = QString::fromUtf8(( *it )->getLayerName() );
if ( palGeometry->isDiagram() )
{
QgsFeature feature;
//render diagram
QHash<QgsVectorLayer*, QgsDiagramLayerSettings>::iterator dit = mActiveDiagramLayers.begin();
for ( dit = mActiveDiagramLayers.begin(); dit != mActiveDiagramLayers.end(); ++dit )
{
if ( dit.key() && dit.key()->id().append( "d" ) == layerName )
{
palGeometry->feature( feature );
QgsPoint outPt = xform->transform(( *it )->getX(), ( *it )->getY() );
dit.value().renderer->renderDiagram( palGeometry->diagramAttributes(), context, QPointF( outPt.x(), outPt.y() ) );
dit.value().renderer->renderDiagram( feature, context, QPointF( outPt.x(), outPt.y() ) );
}
}

Expand Down
44 changes: 40 additions & 4 deletions src/core/qgsvectorlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@

#include "qgsmaptopixelgeometrysimplifier.h"

#include "diagram/qgsdiagram.h"

#ifdef TESTPROVIDERLIB
#include <dlfcn.h>
#endif
Expand Down Expand Up @@ -3611,15 +3613,49 @@ void QgsVectorLayer::prepareLabelingAndDiagrams( QgsRenderContext& rendererConte
mDiagramLayerSettings->renderer = mDiagramRenderer;
rendererContext.labelingEngine()->addDiagramLayer( this, mDiagramLayerSettings );
//add attributes needed by the diagram renderer
QList<int> att = mDiagramRenderer->diagramAttributes();
QList<int>::const_iterator attIt = att.constBegin();
QList<QString> att = mDiagramRenderer->diagramAttributes();
QList<QString>::const_iterator attIt = att.constBegin();
for ( ; attIt != att.constEnd(); ++attIt )
{
if ( !attributes.contains( *attIt ) )
QgsExpression* expression = mDiagramRenderer->diagram()->getExpression( *attIt, &pendingFields() );
QStringList columns = expression->referencedColumns();
QStringList::const_iterator columnsIterator = columns.constBegin();
for ( ; columnsIterator != columns.constEnd(); ++columnsIterator )
{
attributes << *attIt;
int index = fieldNameIndex( *columnsIterator );
if ( !attributes.contains( index ) )
{
attributes << index;
}
}
}

QgsLinearlyInterpolatedDiagramRenderer* mLinearlyInterpolatedDiagramRenderer = dynamic_cast<QgsLinearlyInterpolatedDiagramRenderer*>( mDiagramRenderer );
if ( mLinearlyInterpolatedDiagramRenderer != NULL )
{
if ( mLinearlyInterpolatedDiagramRenderer->classificationAttributeIsExpression() )
{
QgsExpression* expression = mDiagramRenderer->diagram()->getExpression( mLinearlyInterpolatedDiagramRenderer->classificationAttributeExpression(), &pendingFields() );
QStringList columns = expression->referencedColumns();
QStringList::const_iterator columnsIterator = columns.constBegin();
for ( ; columnsIterator != columns.constEnd(); ++columnsIterator )
{
int index = fieldNameIndex( *columnsIterator );
if ( !attributes.contains( index ) )
{
attributes << index;
}
}
}
else
{
if ( !attributes.contains( mLinearlyInterpolatedDiagramRenderer->classificationAttribute() ) )
{
attributes << mLinearlyInterpolatedDiagramRenderer->classificationAttribute();
}
}
}

//and the ones needed for data defined diagram positions
if ( mDiagramLayerSettings->xPosColumn >= 0 && !attributes.contains( mDiagramLayerSettings->xPosColumn ) )
{
Expand Down
44 changes: 42 additions & 2 deletions src/ui/qgsdiagrampropertiesbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,26 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="mSizeAttributeExpression">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>Edit expression</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mIconExpressionEditorOpen.svg</normaloff>:/images/themes/default/mIconExpressionEditorOpen.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>16</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="mFindMaximumValueButton">
<property name="text">
Expand Down Expand Up @@ -837,10 +857,30 @@ Leave empty to automatically apply the maximum value.</string>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="mAddAttributeExpression">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>Add expression</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mIconExpressionEditorOpen.svg</normaloff>:/images/themes/default/mIconExpressionEditorOpen.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>16</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="mAddCategoryPushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
Expand All @@ -857,7 +897,7 @@ Leave empty to automatically apply the maximum value.</string>
<item>
<widget class="QPushButton" name="mRemoveCategoryPushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
Expand Down
2 changes: 1 addition & 1 deletion tests/src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ ADD_QGIS_TEST(clippertest testqgsclipper.cpp)
ADD_QGIS_TEST(distanceareatest testqgsdistancearea.cpp)
ADD_QGIS_TEST(applicationtest testqgsapplication.cpp)
ADD_QGIS_TEST(diagramtest testqgsdiagram.cpp)
ADD_QGIS_TEST(diagramexpressiontest testqgsdiagramexpression.cpp)
ADD_QGIS_TEST(expressiontest testqgsexpression.cpp)
ADD_QGIS_TEST(filewritertest testqgsvectorfilewriter.cpp)
ADD_QGIS_TEST(regression992 regression992.cpp)
Expand Down Expand Up @@ -115,4 +116,3 @@ ADD_QGIS_TEST(composerscalebartest testqgscomposerscalebar.cpp )
ADD_QGIS_TEST(ogcutilstest testqgsogcutils.cpp)
ADD_QGIS_TEST(vectorlayercachetest testqgsvectorlayercache.cpp )
ADD_QGIS_TEST(gradienttest testqgsgradients.cpp )

2 changes: 1 addition & 1 deletion tests/src/core/testqgsdiagram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class TestQgsDiagram: public QObject
col1.setAlphaF( 0.5 );
col2.setAlphaF( 0.5 );
ds.categoryColors = QList<QColor>() << col1 << col2;
ds.categoryIndices = QList<int>() << 3 << 4; // Pilots / Cabin Crew
ds.categoryAttributes = QList<QString>() << "\"Pilots\"" << "\"Cabin Crew\"";
ds.maxScaleDenominator = -1;
ds.minScaleDenominator = -1;
ds.minimumSize = 0;
Expand Down
180 changes: 180 additions & 0 deletions tests/src/core/testqgsdiagramexpression.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/***************************************************************************
testqgsdiagram.cpp
--------------------------------------
Date : Sep 7 2012
Copyright : (C) 2012 by Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* 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 <QtTest>
#include <QObject>
#include <QString>
#include <QStringList>
#include <QObject>
#include <QApplication>
#include <QFileInfo>
#include <QDir>
#include <QDesktopServices>
#include <QPainter>

#include <iostream>
//qgis includes...
// #include <qgisapp.h>
#include <diagram/qgspiediagram.h>
#include <qgsdiagramrendererv2.h>
#include <qgscomposition.h>
#include <qgscompositionchecker.h>
#include <qgscomposermap.h>
#include <qgsmaprenderer.h>
#include <qgsmaplayer.h>
#include <qgsvectordataprovider.h>
#include <qgsvectorlayer.h>
#include <qgsapplication.h>
#include <qgsproviderregistry.h>
#include <qgsmaplayerregistry.h>
#include <qgsrendererv2.h>
//qgis test includes
#include "qgsrenderchecker.h"
#include "qgspallabeling.h"

/** \ingroup UnitTests
* This is a unit test for the vector layer class.
*/
class TestQgsDiagramExpression: public QObject
{
Q_OBJECT;
private:
bool mTestHasError;
QgsMapRenderer * mMapRenderer;
QgsVectorLayer * mPointsLayer;
QgsComposition * mComposition;
QString mTestDataDir;
QString mReport;
QgsPieDiagram * mPieDiagram;
QgsComposerMap * mComposerMap;

private slots:


// will be called before the first testfunction is executed.
void initTestCase()
{
mTestHasError = false;
QgsApplication::init();
QgsApplication::initQgis();
QgsApplication::showSettings();

//create some objects that will be used in all tests...

//
//create a non spatial layer that will be used in all tests...
//
QString myDataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt
mTestDataDir = myDataDir + QDir::separator();

//
//create a point layer that will be used in all tests...
//
QString myPointsFileName = mTestDataDir + "points.shp";
QFileInfo myPointFileInfo( myPointsFileName );
mPointsLayer = new QgsVectorLayer( myPointFileInfo.filePath(),
myPointFileInfo.completeBaseName(), "ogr" );

// Register the layer with the registry
QgsMapLayerRegistry::instance()->addMapLayers(
QList<QgsMapLayer *>() << mPointsLayer );

// Create diagrams
mPieDiagram = new QgsPieDiagram();

// Create map composition to draw on
mMapRenderer = new QgsMapRenderer();
mMapRenderer->setLayerSet( QStringList() << mPointsLayer->id() );
mMapRenderer->setLabelingEngine( new QgsPalLabeling() );
mComposition = new QgsComposition( mMapRenderer );
mComposition->setPaperSize( 297, 210 ); // A4 landscape
mComposerMap = new QgsComposerMap( mComposition, 20, 20, 200, 100 );
mComposerMap->setFrameEnabled( true );
mComposition->addComposerMap( mComposerMap );

mReport += "<h1>Diagram Tests</h1>\n";
}

// will be called after the last testfunction was executed.
void cleanupTestCase()
{
QString myReportFile = QDir::tempPath() + QDir::separator() + "qgistest.html";
QFile myFile( myReportFile );
if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
{
QTextStream myQTextStream( &myFile );
myQTextStream << mReport;
myFile.close();
}

delete mComposerMap;
delete mComposition;
delete mMapRenderer;
delete mPointsLayer;
}

void init() {};// will be called before each testfunction is executed.
void cleanup() {};// will be called after every testfunction.

// will be called after the last testfunction was executed.
void testPieDiagramExpression()
{
QgsDiagramSettings ds;
QColor col1 = Qt::red;
QColor col2 = Qt::yellow;
col1.setAlphaF( 0.5 );
col2.setAlphaF( 0.5 );
ds.categoryColors = QList<QColor>() << col1 << col2;
ds.categoryAttributes = QList<QString>() << "ln(Pilots + 1)" << "ln(\"Cabin Crew\" + 1)";
ds.maxScaleDenominator = -1;
ds.minScaleDenominator = -1;
ds.minimumSize = 0;
ds.penColor = Qt::green;
ds.penWidth = .5;
ds.scaleByArea = true;
ds.sizeType = QgsDiagramSettings::MM;
ds.size = QSizeF( 15, 15 );
ds.angleOffset = 0;


QgsLinearlyInterpolatedDiagramRenderer *dr = new QgsLinearlyInterpolatedDiagramRenderer();
dr->setLowerValue( 0.0 );
dr->setLowerSize( QSizeF( 0.0, 0.0 ) );
dr->setUpperValue( 10 );
dr->setUpperSize( QSizeF( 100, 100 ) );
dr->setClassificationAttributeIsExpression( true );
dr->setClassificationAttributeExpression( "ln(Staff + 1)" );
dr->setDiagram( mPieDiagram );
dr->setDiagramSettings( ds );
mPointsLayer->setDiagramRenderer( dr );

QgsDiagramLayerSettings dls = QgsDiagramLayerSettings();
dls.placement = QgsDiagramLayerSettings::OverPoint;
dls.renderer = dr;

dynamic_cast<QgsPalLabeling*>( mMapRenderer->labelingEngine() )->setShowingAllLabels( true );

mPointsLayer->setDiagramLayerSettings( dls );

mComposerMap->setNewExtent( QgsRectangle( -122, -79, -70, 47 ) );
QgsCompositionChecker checker( "piediagram_expression", mComposition );

QVERIFY( checker.testComposition( mReport ) );

mPointsLayer->setDiagramRenderer( 0 );
}
};

QTEST_MAIN( TestQgsDiagramExpression )
#include "moc_testqgsdiagramexpression.cxx"
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.