303 changes: 58 additions & 245 deletions src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ static QPointF _rotatedOffset( const QPointF& offset, double angle )
//////

QgsSimpleMarkerSymbolLayerV2::QgsSimpleMarkerSymbolLayerV2( QString name, QColor color, QColor borderColor, double size, double angle, QgsSymbolV2::ScaleMethod scaleMethod )
: mOutlineWidth( 0 ), mOutlineWidthUnit( QgsSymbolV2::MM ), mNameExpression( 0 ), mColorExpression( 0 ), mColorBorderExpression( 0 ), mOutlineWidthExpression( 0 ),
mSizeExpression( 0 ), mAngleExpression( 0 ), mOffsetExpression( 0 )
: mOutlineWidth( 0 ), mOutlineWidthUnit( QgsSymbolV2::MM )
{
mName = name;
mColor = color;
Expand Down Expand Up @@ -162,15 +161,15 @@ void QgsSimpleMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& contex
mSelPen = QPen( selPenColor );
mSelPen.setWidthF( mOutlineWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOutlineWidthUnit ) );

bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation;
bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale || mSizeExpression;
bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || dataDefinedProperty( "angle" );
bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale || dataDefinedProperty( "size" );

// use caching only when:
// - size, rotation, shape, color, border color is not data-defined
// - drawing to screen (not printer)
mUsingCache = !hasDataDefinedRotation && !hasDataDefinedSize && !context.renderContext().forceVectorOutput()
&& !mNameExpression && !mColorExpression && !mColorBorderExpression && !mOutlineWidthExpression &&
!mSizeExpression && !mAngleExpression;
&& !dataDefinedProperty( "name" ) && !dataDefinedProperty( "color" ) && !dataDefinedProperty( "color_border" ) && !dataDefinedProperty( "outline_width" ) &&
!dataDefinedProperty( "size" );

// use either QPolygonF or QPainterPath for drawing
// TODO: find out whether drawing directly doesn't bring overhead - if not, use it for all shapes
Expand Down Expand Up @@ -432,9 +431,10 @@ void QgsSimpleMarkerSymbolLayerV2::markerOffset( QgsSymbolV2RenderContext& conte
offsetX = mOffset.x();
offsetY = mOffset.y();

if ( mOffsetExpression )
QgsExpression* offsetExpression = expression( "offset" );
if ( offsetExpression )
{
QPointF offset = QgsSymbolLayerV2Utils::decodePoint( mOffsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
QPointF offset = QgsSymbolLayerV2Utils::decodePoint( offsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
offsetX = offset.x();
offsetY = offset.y();
}
Expand All @@ -460,17 +460,19 @@ void QgsSimpleMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV

//angle
double angle = mAngle;
if ( mAngleExpression )
QgsExpression* angleExpression = expression( "angle" );
if ( angleExpression )
{
angle = mAngleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
angle = angleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
}
if ( angle )
off = _rotatedOffset( off, angle );

//data defined shape?
if ( mNameExpression )
QgsExpression* nameExpression = expression( "name" );
if ( nameExpression )
{
QString name = mNameExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
QString name = nameExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
if ( !prepareShape( name ) ) // drawing as a polygon
{
preparePath( name ); // drawing as a painter path
Expand All @@ -490,8 +492,10 @@ void QgsSimpleMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV
{
QMatrix transform;

bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || mAngleExpression;
bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale || mSizeExpression;

bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || angleExpression;
QgsExpression* sizeExpression = expression( "size" );
bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale || sizeExpression;

// move to the desired position
transform.translate( point.x() + off.x(), point.y() + off.y() );
Expand All @@ -500,9 +504,9 @@ void QgsSimpleMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV
if ( hasDataDefinedSize )
{
double scaledSize = mSize;
if ( mSizeExpression )
if ( sizeExpression )
{
scaledSize = mSizeExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
scaledSize = sizeExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
}
scaledSize *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mSizeUnit );

Expand All @@ -525,18 +529,21 @@ void QgsSimpleMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV
transform.rotate( angle );
}

if ( mColorExpression )
QgsExpression* colorExpression = expression( "color" );
QgsExpression* colorBorderExpression = expression( "color_border" );
QgsExpression* outlineWidthExpression = expression( "outline_width" );
if ( colorExpression )
{
mBrush.setColor( QgsSymbolLayerV2Utils::decodeColor( mColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
mBrush.setColor( QgsSymbolLayerV2Utils::decodeColor( colorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
}
if ( mColorBorderExpression )
if ( colorBorderExpression )
{
mPen.setColor( QgsSymbolLayerV2Utils::decodeColor( mColorBorderExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
mSelPen.setColor( QgsSymbolLayerV2Utils::decodeColor( mColorBorderExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
mPen.setColor( QgsSymbolLayerV2Utils::decodeColor( colorBorderExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
mSelPen.setColor( QgsSymbolLayerV2Utils::decodeColor( colorBorderExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
}
if ( mOutlineWidthExpression )
if ( outlineWidthExpression )
{
double outlineWidth = mOutlineWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
double outlineWidth = outlineWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
mPen.setWidthF( outlineWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOutlineWidthUnit ) );
mSelPen.setWidthF( outlineWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOutlineWidthUnit ) );
}
Expand Down Expand Up @@ -568,34 +575,27 @@ QgsStringMap QgsSimpleMarkerSymbolLayerV2::properties() const
map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );

//data define properties
if ( mNameExpression )
{
map["name_expression"] = mNameExpression->dump();
}
if ( mColorExpression )
{
map["color_expression"] = mColorExpression->dump();
}
if ( mColorBorderExpression )
{
map["color_border_expression"] = mColorBorderExpression->dump();
}
if ( mOutlineWidthExpression )
{
map["outline_width_expression"] = mOutlineWidthExpression->dump();
}
if ( mSizeExpression )
{
map["size_expression"] = mSizeExpression->dump();
}
if ( mAngleExpression )
{
map["angle_expression"] = mAngleExpression->dump();
}
if ( mOffsetExpression )
{
map["offset_expression"] = mOffsetExpression->dump();
}
const QgsExpression* nameExpression = dataDefinedProperty( "name" );
if ( nameExpression )
map["name_expression"] = nameExpression->dump();
const QgsExpression* colorExpression = dataDefinedProperty( "color" );
if ( colorExpression )
map["color_expression"] = colorExpression->dump();
const QgsExpression* colorBorderExpression = dataDefinedProperty( "color_border" );
if ( colorBorderExpression )
map["color_border_expression"] = colorBorderExpression->dump();
const QgsExpression* outlineWidthExpression = dataDefinedProperty( "outline_width" );
if ( outlineWidthExpression )
map["outline_width_expression"] = outlineWidthExpression->dump();
const QgsExpression* sizeExpression = dataDefinedProperty( "size" );
if ( sizeExpression )
map["size_expression"] = sizeExpression->dump();
const QgsExpression* angleExpression = dataDefinedProperty( "angle" );
if ( angleExpression )
map["angle_expression"] = angleExpression->dump();
const QgsExpression* offsetExpression = dataDefinedProperty( "offset" );
if ( offsetExpression )
map["offset_expression"] = offsetExpression->dump();
return map;
}

Expand All @@ -608,35 +608,15 @@ QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::clone() const
m->setOutlineWidth( mOutlineWidth );
m->setOutlineWidthUnit( mOutlineWidthUnit );

//data defined properties
if ( mNameExpression )
{
m->setDataDefinedProperty( "name", mNameExpression->dump() );
}
if ( mColorExpression )
{
m->setDataDefinedProperty( "color", mColorExpression->dump() );
}
if ( mColorBorderExpression )
{
m->setDataDefinedProperty( "color_border", mColorBorderExpression->dump() );
}
if ( mOutlineWidthExpression )
{
m->setDataDefinedProperty( "outline_width", mOutlineWidthExpression->dump() );
}
if ( mSizeExpression )
{
m->setDataDefinedProperty( "size", mSizeExpression->dump() );
}
if ( mAngleExpression )
QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
{
m->setDataDefinedProperty( "angle", mAngleExpression->dump() );
}
if ( mOffsetExpression )
{
m->setDataDefinedProperty( "offset", mOffsetExpression->dump() );
if ( ddIt.value() )
{
m->setDataDefinedProperty( ddIt.key(), ddIt.value()->dump() );
}
}

return m;
}

Expand Down Expand Up @@ -728,149 +708,6 @@ QString QgsSimpleMarkerSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, dou
return ogrString;
}

const QgsExpression* QgsSimpleMarkerSymbolLayerV2::dataDefinedProperty( const QString& property ) const
{
if ( property == "name" )
{
return mNameExpression;
}
else if ( property == "color" )
{
return mColorExpression;
}
else if ( property == "color_border" )
{
return mColorBorderExpression;
}
else if ( property == "outline_width" )
{
return mOutlineWidthExpression;
}
else if ( property == "size" )
{
return mSizeExpression;
}
else if ( property == "angle" )
{
return mAngleExpression;
}
else if ( property == "offset" )
{
return mOffsetExpression;
}
return 0;
}

QString QgsSimpleMarkerSymbolLayerV2::dataDefinedPropertyString( const QString& property ) const
{
const QgsExpression* ex = dataDefinedProperty( property );
return ex ? ex->dump() : QString();
}

void QgsSimpleMarkerSymbolLayerV2::setDataDefinedProperty( const QString& property, const QString& expressionString )
{
if ( property == "name" )
{
delete mNameExpression; mNameExpression = new QgsExpression( expressionString );
}
else if ( property == "color" )
{
delete mColorExpression; mColorExpression = new QgsExpression( expressionString );
}
else if ( property == "color_border" )
{
delete mColorBorderExpression; mColorBorderExpression = new QgsExpression( expressionString );
}
else if ( property == "outline_width" )
{
delete mOutlineWidthExpression; mOutlineWidthExpression = new QgsExpression( expressionString );
}
else if ( property == "size" )
{
delete mSizeExpression; mSizeExpression = new QgsExpression( expressionString );
}
else if ( property == "angle" )
{
delete mAngleExpression; mAngleExpression = new QgsExpression( expressionString );
}
else if ( property == "offset" )
{
delete mOffsetExpression; mOffsetExpression = new QgsExpression( expressionString );
}
}

void QgsSimpleMarkerSymbolLayerV2::removeDataDefinedProperty( const QString& property )
{
if ( property == "name" )
{
delete mNameExpression; mNameExpression = 0;
}
else if ( property == "color" )
{
delete mColorExpression; mColorExpression = 0;
}
else if ( property == "color_border" )
{
delete mColorBorderExpression; mColorBorderExpression = 0;
}
else if ( property == "outline_width" )
{
delete mOutlineWidthExpression; mOutlineWidthExpression = 0;
}
else if ( property == "size" )
{
delete mSizeExpression; mSizeExpression = 0;
}
else if ( property == "angle" )
{
delete mAngleExpression; mAngleExpression = 0;
}
else if ( property == "offset" )
{
delete mOffsetExpression; mOffsetExpression = 0;
}
}

void QgsSimpleMarkerSymbolLayerV2::removeDataDefinedProperties()
{
delete mNameExpression; mNameExpression = 0;
delete mColorExpression; mColorExpression = 0;
delete mColorBorderExpression; mColorBorderExpression = 0;
delete mOutlineWidthExpression; mOutlineWidthExpression = 0;
delete mSizeExpression; mSizeExpression = 0;
delete mAngleExpression; mAngleExpression = 0;
delete mOffsetExpression; mOffsetExpression = 0;
}

QSet<QString> QgsSimpleMarkerSymbolLayerV2::usedAttributes() const
{
QSet<QString> attributes;

//add data defined attributes
QStringList columns;
if ( mNameExpression )
columns.append( mNameExpression->referencedColumns() );
if ( mColorExpression )
columns.append( mColorExpression->referencedColumns() );
if ( mColorBorderExpression )
columns.append( mColorBorderExpression->referencedColumns() );
if ( mOutlineWidthExpression )
columns.append( mOutlineWidthExpression->referencedColumns() );
if ( mSizeExpression )
columns.append( mSizeExpression->referencedColumns() );
if ( mAngleExpression )
columns.append( mAngleExpression->referencedColumns() );
if ( mOffsetExpression )
columns.append( mOffsetExpression->referencedColumns() );

QStringList::const_iterator it = columns.constBegin();
for ( ; it != columns.constEnd(); ++it )
{
attributes.insert( *it );
}
return attributes;
}

QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::createFromSld( QDomElement &element )
{
QgsDebugMsg( "Entered." );
Expand Down Expand Up @@ -919,30 +756,6 @@ void QgsSimpleMarkerSymbolLayerV2::drawMarker( QPainter* p, QgsSymbolV2RenderCon
}
}

void QgsSimpleMarkerSymbolLayerV2::prepareExpressions( const QgsVectorLayer* vl )
{
if ( !vl )
{
return;
}

const QgsFields& fields = vl->pendingFields();
if ( mNameExpression )
mNameExpression->prepare( fields );
if ( mColorExpression )
mColorExpression->prepare( fields );
if ( mColorBorderExpression )
mColorBorderExpression->prepare( fields );
if ( mOutlineWidthExpression )
mOutlineWidthExpression->prepare( fields );
if ( mSizeExpression )
mSizeExpression->prepare( fields );
if ( mAngleExpression )
mAngleExpression->prepare( fields );
if ( mOffsetExpression )
mOffsetExpression->prepare( fields );
}

//////////


Expand Down
19 changes: 0 additions & 19 deletions src/core/symbology-ng/qgsmarkersymbollayerv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,6 @@ class CORE_EXPORT QgsSimpleMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
QgsSymbolV2::OutputUnit outlineWidthUnit() const { return mOutlineWidthUnit; }
void setOutlineWidthUnit( QgsSymbolV2::OutputUnit u ) { mOutlineWidthUnit = u; }

const QgsExpression* dataDefinedProperty( const QString& property ) const;
QString dataDefinedPropertyString( const QString& property ) const;
void setDataDefinedProperty( const QString& property, const QString& expressionString );
void removeDataDefinedProperty( const QString& property );
void removeDataDefinedProperties();

QSet<QString> usedAttributes() const;

protected:

void drawMarker( QPainter* p, QgsSymbolV2RenderContext& context );
Expand All @@ -108,18 +100,7 @@ class CORE_EXPORT QgsSimpleMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
QImage mSelCache;
bool mUsingCache;

//data defined properties
QgsExpression* mNameExpression;
QgsExpression* mColorExpression;
QgsExpression* mColorBorderExpression;
QgsExpression* mOutlineWidthExpression;
QgsExpression* mSizeExpression;
QgsExpression* mAngleExpression;
QgsExpression* mOffsetExpression;

private:
//helper functions for data defined symbology
void prepareExpressions( const QgsVectorLayer* vl );
void markerOffset( QgsSymbolV2RenderContext& context, double& offsetX, double& offsetY );
};

Expand Down
95 changes: 95 additions & 0 deletions src/core/symbology-ng/qgssymbollayerv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,108 @@

#include "qgssymbollayerv2.h"
#include "qgsclipper.h"
#include "qgsexpression.h"
#include "qgsrendercontext.h"
#include "qgsvectorlayer.h"

#include <QSize>
#include <QPainter>
#include <QPointF>
#include <QPolygonF>

const QgsExpression* QgsSymbolLayerV2::dataDefinedProperty( const QString& property ) const
{
QMap< QString, QgsExpression* >::const_iterator it = mDataDefinedProperties.find( property );
if ( it != mDataDefinedProperties.constEnd() )
{
return it.value();
}
return 0;
}

QgsExpression* QgsSymbolLayerV2::expression( const QString& property )
{
QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.find( property );
if ( it != mDataDefinedProperties.end() )
{
return it.value();
}
return 0;
}

QString QgsSymbolLayerV2::dataDefinedPropertyString( const QString& property ) const
{
const QgsExpression* ex = dataDefinedProperty( property );
return ex ? ex->dump() : QString();
}

void QgsSymbolLayerV2::setDataDefinedProperty( const QString& property, const QString& expressionString )
{
removeDataDefinedProperty( property );
mDataDefinedProperties.insert( property, new QgsExpression( expressionString ) );
}

void QgsSymbolLayerV2::removeDataDefinedProperty( const QString& property )
{
QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.find( property );
if ( it != mDataDefinedProperties.end() )
{
delete( it.value() );
mDataDefinedProperties.erase( it );
}
}

void QgsSymbolLayerV2::removeDataDefinedProperties()
{
QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.begin();
for ( ; it != mDataDefinedProperties.constEnd(); ++it )
{
delete( it.value() );
}
mDataDefinedProperties.clear();
}

void QgsSymbolLayerV2::prepareExpressions( const QgsVectorLayer* vl )
{
if ( !vl )
{
return;
}

const QgsFields& fields = vl->pendingFields();
QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.begin();
for ( ; it != mDataDefinedProperties.end(); ++it )
{
if ( it.value() )
{
it.value()->prepare( fields );
}
}
}

QSet<QString> QgsSymbolLayerV2::usedAttributes() const
{
QSet<QString> attributes;
QStringList columns;

QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
{
if ( ddIt.value() )
{
columns.append( ddIt.value()->referencedColumns() );
}
}

QStringList::const_iterator it = columns.constBegin();
for ( ; it != columns.constEnd(); ++it )
{
attributes.insert( *it );
}
return attributes;
}


QgsMarkerSymbolLayerV2::QgsMarkerSymbolLayerV2( bool locked )
: QgsSymbolLayerV2( QgsSymbolV2::Marker, locked ), mSizeUnit( QgsSymbolV2::MM ), mOffsetUnit( QgsSymbolV2::MM )
{
Expand Down
16 changes: 10 additions & 6 deletions src/core/symbology-ng/qgssymbollayerv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,13 @@ class CORE_EXPORT QgsSymbolLayerV2
int renderingPass() const { return mRenderingPass; }

// symbol layers normally only use additional attributes to provide data defined settings
virtual QSet<QString> usedAttributes() const { return QSet<QString>(); }
virtual QSet<QString> usedAttributes() const;

virtual const QgsExpression* dataDefinedProperty( const QString& property ) const { Q_UNUSED( property ); return 0; } //= 0;
virtual QString dataDefinedPropertyString( const QString& property ) const { Q_UNUSED( property ); return QString(); } //= 0;
virtual void setDataDefinedProperty( const QString& property, const QString& expressionString ) { Q_UNUSED( property ); Q_UNUSED( expressionString ); } //=0;
virtual void removeDataDefinedProperty( const QString& property ) { Q_UNUSED( property ); } //=0;
virtual void removeDataDefinedProperties() {} //=0;
virtual const QgsExpression* dataDefinedProperty( const QString& property ) const;
virtual QString dataDefinedPropertyString( const QString& property ) const;
virtual void setDataDefinedProperty( const QString& property, const QString& expressionString );
virtual void removeDataDefinedProperty( const QString& property );
virtual void removeDataDefinedProperties();

protected:
QgsSymbolLayerV2( QgsSymbolV2::SymbolType type, bool locked = false )
Expand All @@ -95,11 +95,15 @@ class CORE_EXPORT QgsSymbolLayerV2
QColor mColor;
int mRenderingPass;

QMap< QString, QgsExpression* > mDataDefinedProperties;

// Configuration of selected symbology implementation
static const bool selectionIsOpaque = true; // Selection ignores symbol alpha
static const bool selectFillBorder = false; // Fill symbol layer also selects border symbology
static const bool selectFillStyle = false; // Fill symbol uses symbol layer style..

virtual void prepareExpressions( const QgsVectorLayer* vl );
virtual QgsExpression* expression( const QString& property );
};

//////////////////////
Expand Down