Skip to content

Commit

Permalink
Data defined properties for point pattern symbollayer
Browse files Browse the repository at this point in the history
  • Loading branch information
mhugent committed Mar 30, 2013
1 parent 1ea6a72 commit 9acdcb7
Show file tree
Hide file tree
Showing 6 changed files with 346 additions and 86 deletions.
213 changes: 198 additions & 15 deletions src/core/symbology-ng/qgsfillsymbollayerv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1826,7 +1826,8 @@ QgsSymbolLayerV2* QgsLinePatternFillSymbolLayer::createFromSld( QDomElement &ele

QgsPointPatternFillSymbolLayer::QgsPointPatternFillSymbolLayer(): QgsImageFillSymbolLayer(), mMarkerSymbol( 0 ), mDistanceX( 15 ),
mDistanceXUnit( QgsSymbolV2::MM ), mDistanceY( 15 ), mDistanceYUnit( QgsSymbolV2::MM ), mDisplacementX( 0 ), mDisplacementXUnit( QgsSymbolV2::MM ),
mDisplacementY( 0 ), mDisplacementYUnit( QgsSymbolV2::MM )
mDisplacementY( 0 ), mDisplacementYUnit( QgsSymbolV2::MM ), mDistanceXExpression( 0 ), mDistanceYExpression( 0 ),
mDisplacementXExpression( 0 ), mDisplacementYExpression( 0 )
{
mDistanceX = 15;
mDistanceY = 15;
Expand Down Expand Up @@ -1878,11 +1879,6 @@ QgsSymbolLayerV2* QgsPointPatternFillSymbolLayer::create( const QgsStringMap& pr
layer->setDisplacementY( properties["displacement_y"].toDouble() );
}

/*propertyMap["distance_x_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceXUnit );
propertyMap["distance_y_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceYUnit );
propertyMap["displacement_x_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mDisplacementXUnit );
propertyMap["displacement_y_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mDisplacementYUnit );*/

if ( properties.contains( "distance_x_unit" ) )
{
layer->setDistanceXUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["distance_x_unit"] ) );
Expand All @@ -1900,6 +1896,23 @@ QgsSymbolLayerV2* QgsPointPatternFillSymbolLayer::create( const QgsStringMap& pr
layer->setDisplacementYUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["displacement_y_unit"] ) );
}

//data defined properties
if ( properties.contains( "distance_x_expression" ) )
{
layer->setDataDefinedProperty( "distance_x", properties["distance_x_expression"] );
}
if ( properties.contains( "distance_y_expression" ) )
{
layer->setDataDefinedProperty( "distance_y", properties["distance_y_expression"] );
}
if ( properties.contains( "displacement_x_expression" ) )
{
layer->setDataDefinedProperty( "displacement_x", properties["displacement_x_expression"] );
}
if ( properties.contains( "displacement_y_expression" ) )
{
layer->setDataDefinedProperty( "displacement_y", properties["displacement_y_expression"] );
}
return layer;
}

Expand All @@ -1908,17 +1921,18 @@ QString QgsPointPatternFillSymbolLayer::layerType() const
return "PointPatternFill";
}

void QgsPointPatternFillSymbolLayer::startRender( QgsSymbolV2RenderContext& context )
void QgsPointPatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext& context, QBrush& brush, double distanceX, double distanceY,
double displacementX, double displacementY )
{
//render 3 rows and columns in one go to easily incorporate displacement
const QgsRenderContext& ctx = context.renderContext();
double width = mDistanceX * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDistanceXUnit ) * 2.0;
double height = mDistanceY * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDistanceYUnit ) * 2.0;
double width = distanceX * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDistanceXUnit ) * 2.0;
double height = distanceY * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDistanceYUnit ) * 2.0;

if ( width > 10000 || height > 10000 ) //protect symbol layer from eating too much memory
{
QImage img;
mBrush.setTextureImage( img );
brush.setTextureImage( img );
return;
}

Expand Down Expand Up @@ -1947,8 +1961,8 @@ void QgsPointPatternFillSymbolLayer::startRender( QgsSymbolV2RenderContext& cont
mMarkerSymbol->renderPoint( QPointF( width, height ), context.feature(), pointRenderContext );

//render displaced points
double displacementPixelX = mDisplacementX * QgsSymbolLayerV2Utils::lineWidthScaleFactor( ctx, mDisplacementXUnit );
double displacementPixelY = mDisplacementY * QgsSymbolLayerV2Utils::lineWidthScaleFactor( ctx, mDisplacementYUnit );
double displacementPixelX = displacementX * QgsSymbolLayerV2Utils::lineWidthScaleFactor( ctx, mDisplacementXUnit );
double displacementPixelY = displacementY * QgsSymbolLayerV2Utils::lineWidthScaleFactor( ctx, mDisplacementYUnit );
mMarkerSymbol->renderPoint( QPointF( width / 2.0, -displacementPixelY ), context.feature(), pointRenderContext );
mMarkerSymbol->renderPoint( QPointF( displacementPixelX, height / 2.0 ), context.feature(), pointRenderContext );
mMarkerSymbol->renderPoint( QPointF( width / 2.0 + displacementPixelX, height / 2.0 - displacementPixelY ), context.feature(), pointRenderContext );
Expand All @@ -1962,15 +1976,20 @@ void QgsPointPatternFillSymbolLayer::startRender( QgsSymbolV2RenderContext& cont
{
QImage transparentImage = patternImage.copy();
QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
mBrush.setTextureImage( transparentImage );
brush.setTextureImage( transparentImage );
}
else
{
mBrush.setTextureImage( patternImage );
brush.setTextureImage( patternImage );
}
QTransform brushTransform;
brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
mBrush.setTransform( brushTransform );
brush.setTransform( brushTransform );
}

void QgsPointPatternFillSymbolLayer::startRender( QgsSymbolV2RenderContext& context )
{
applyPattern( context, mBrush, mDistanceX, mDistanceY, mDisplacementX, mDisplacementY );

if ( mOutline )
{
Expand All @@ -1997,6 +2016,24 @@ QgsStringMap QgsPointPatternFillSymbolLayer::properties() const
propertyMap["distance_y_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceYUnit );
propertyMap["displacement_x_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mDisplacementXUnit );
propertyMap["displacement_y_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mDisplacementYUnit );

//data defined properties
if ( mDistanceXExpression )
{
propertyMap["distance_x_expression"] = mDistanceXExpression->dump();
}
if ( mDistanceYExpression )
{
propertyMap["distance_y_expression"] = mDistanceYExpression->dump();
}
if ( mDisplacementXExpression )
{
propertyMap["displacement_x_expression"] = mDisplacementXExpression->dump();
}
if ( mDisplacementYExpression )
{
propertyMap["displacement_y_expression"] = mDisplacementYExpression->dump();
}
return propertyMap;
}

Expand Down Expand Up @@ -2073,6 +2110,152 @@ bool QgsPointPatternFillSymbolLayer::setSubSymbol( QgsSymbolV2* symbol )
return true;
}

const QgsExpression* QgsPointPatternFillSymbolLayer::dataDefinedProperty( const QString& property ) const
{
if ( property == "distance_x" )
{
return mDistanceXExpression;
}
else if ( property == "distance_x" )
{
return mDistanceYExpression;
}
else if ( property == "displacement_x" )
{
return mDisplacementXExpression;
}
else if ( property == "displacement_y" )
{
return mDisplacementYExpression;
}
return 0;
}

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

void QgsPointPatternFillSymbolLayer::setDataDefinedProperty( const QString& property, const QString& expressionString )
{
if ( property == "distance_x" )
{
delete mDistanceXExpression; mDistanceXExpression = new QgsExpression( expressionString );
}
else if ( property == "distance_x" )
{
delete mDistanceYExpression; mDistanceYExpression = new QgsExpression( expressionString );
}
else if ( property == "displacement_x" )
{
delete mDisplacementXExpression; mDisplacementXExpression = new QgsExpression( expressionString );
}
else if ( property == "displacement_y" )
{
delete mDisplacementYExpression; mDisplacementYExpression = new QgsExpression( expressionString );
}
}

void QgsPointPatternFillSymbolLayer::removeDataDefinedProperty( const QString& property )
{
if ( property == "distance_x" )
{
delete mDistanceXExpression; mDistanceXExpression = 0;
}
else if ( property == "distance_x" )
{
delete mDistanceYExpression; mDistanceYExpression = 0;
}
else if ( property == "displacement_x" )
{
delete mDisplacementXExpression; mDisplacementXExpression = 0;
}
else if ( property == "displacement_y" )
{
delete mDisplacementYExpression; mDisplacementYExpression = 0;
}
}

void QgsPointPatternFillSymbolLayer::removeDataDefinedProperties()
{
delete mDistanceXExpression; mDistanceXExpression = 0;
delete mDistanceYExpression; mDistanceYExpression = 0;
delete mDisplacementXExpression; mDisplacementXExpression = 0;
delete mDisplacementYExpression; mDisplacementYExpression = 0;
}

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

//add data defined attributes
QStringList columns;
if ( mDistanceXExpression )
columns.append( mDistanceXExpression->referencedColumns() );
if ( mDistanceYExpression )
columns.append( mDistanceYExpression->referencedColumns() );
if ( mDisplacementXExpression )
columns.append( mDisplacementXExpression->referencedColumns() );
if ( mDisplacementYExpression )
columns.append( mDisplacementYExpression->referencedColumns() );

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

void QgsPointPatternFillSymbolLayer::applyDataDefinedSettings( const QgsSymbolV2RenderContext& context )
{
if ( !mDistanceXExpression && !mDistanceYExpression && !mDisplacementXExpression && !mDisplacementYExpression )
{
return;
}

double distanceX = mDistanceX;
if ( mDistanceXExpression )
{
distanceX = mDistanceXExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
}
double distanceY = mDistanceY;
if ( mDistanceYExpression )
{
distanceY = mDistanceYExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
}
double displacementX = mDisplacementX;
if ( mDisplacementXExpression )
{
displacementX = mDisplacementXExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
}
double displacementY = mDisplacementY;
if ( mDisplacementYExpression )
{
displacementY = mDisplacementYExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
}
applyPattern( context, mBrush, distanceX, distanceY, displacementX, displacementY );
}

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

const QgsFields& fields = vl->pendingFields();
if ( mDistanceXExpression )
mDistanceXExpression->prepare( fields );
if ( mDistanceYExpression )
mDistanceYExpression->prepare( fields );
if ( mDisplacementXExpression )
mDisplacementXExpression->prepare( fields );
if ( mDisplacementYExpression )
mDisplacementYExpression->prepare( fields );
}

//////////////


Expand Down
20 changes: 20 additions & 0 deletions src/core/symbology-ng/qgsfillsymbollayerv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,14 @@ class CORE_EXPORT QgsPointPatternFillSymbolLayer: public QgsImageFillSymbolLayer
void setOutputUnit( QgsSymbolV2::OutputUnit unit );
QgsSymbolV2::OutputUnit outputUnit() const;

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:
QgsMarkerSymbolV2* mMarkerSymbol;
double mDistanceX;
Expand All @@ -386,6 +394,18 @@ class CORE_EXPORT QgsPointPatternFillSymbolLayer: public QgsImageFillSymbolLayer
QgsSymbolV2::OutputUnit mDisplacementXUnit;
double mDisplacementY;
QgsSymbolV2::OutputUnit mDisplacementYUnit;

QgsExpression* mDistanceXExpression;
QgsExpression* mDistanceYExpression;
QgsExpression* mDisplacementXExpression;
QgsExpression* mDisplacementYExpression;

void applyDataDefinedSettings( const QgsSymbolV2RenderContext& context );

private:
void applyPattern( const QgsSymbolV2RenderContext& context, QBrush& brush, double distanceX, double distanceY,
double displacementX, double displacementY );
void prepareExpressions( const QgsVectorLayer* vl );
};

class CORE_EXPORT QgsCentroidFillSymbolLayerV2 : public QgsFillSymbolLayerV2
Expand Down
2 changes: 1 addition & 1 deletion src/core/symbology-ng/qgssymbolv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ QgsSymbolV2::~QgsSymbolV2()

QgsSymbolV2::OutputUnit QgsSymbolV2::outputUnit() const
{
QgsSymbolV2::OutputUnit unit;
QgsSymbolV2::OutputUnit unit = QgsSymbolV2::MM;

QgsSymbolLayerV2List::const_iterator it = mLayers.constBegin();
for ( ; it != mLayers.constEnd(); ++it )
Expand Down
32 changes: 32 additions & 0 deletions src/gui/symbology-ng/qgssymbollayerv2widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1729,6 +1729,38 @@ void QgsPointPatternFillSymbolLayerWidget::on_mVerticalDisplacementUnitComboBox_
}
}

void QgsPointPatternFillSymbolLayerWidget::on_mDataDefinedPropertiesButton_clicked()
{
if ( !mLayer )
{
return;
}

QMap<QString, QPair< QString, QString> > dataDefinedProperties;
dataDefinedProperties.insert( "distance_x", qMakePair( tr( "Horizontal distance" ), mLayer->dataDefinedPropertyString( "distance_x" ) ) );
dataDefinedProperties.insert( "distance_y", qMakePair( tr( "Vertical distance" ), mLayer->dataDefinedPropertyString( "distance_y" ) ) );
dataDefinedProperties.insert( "displacement_x", qMakePair( tr( "Horizontal displacement" ), mLayer->dataDefinedPropertyString( "displacement_x" ) ) );
dataDefinedProperties.insert( "displacement_y", qMakePair( tr( "Vertical displacement" ), mLayer->dataDefinedPropertyString( "displacement_y" ) ) );

QgsDataDefinedSymbolDialog d( dataDefinedProperties, mVectorLayer );
if ( d.exec() == QDialog::Accepted )
{
//empty all existing properties first
mLayer->removeDataDefinedProperties();

QMap<QString, QString> properties = d.dataDefinedProperties();
QMap<QString, QString>::const_iterator it = properties.constBegin();
for ( ; it != properties.constEnd(); ++it )
{
if ( !it.value().isEmpty() )
{
mLayer->setDataDefinedProperty( it.key(), it.value() );
}
}
emit changed();
}
}

/////////////

QgsFontMarkerSymbolLayerV2Widget::QgsFontMarkerSymbolLayerV2Widget( const QgsVectorLayer* vl, QWidget* parent )
Expand Down
1 change: 1 addition & 0 deletions src/gui/symbology-ng/qgssymbollayerv2widget.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ class GUI_EXPORT QgsPointPatternFillSymbolLayerWidget: public QgsSymbolLayerV2Wi
void on_mVerticalDistanceUnitComboBox_currentIndexChanged( int index );
void on_mHorizontalDisplacementUnitComboBox_currentIndexChanged( int index );
void on_mVerticalDisplacementUnitComboBox_currentIndexChanged( int index );
void on_mDataDefinedPropertiesButton_clicked();
};

/////////
Expand Down
Loading

0 comments on commit 9acdcb7

Please sign in to comment.