Skip to content

Commit

Permalink
[FEATURE][symbology] Allow data-defined offset for fill symbol layers
Browse files Browse the repository at this point in the history
Any fill symbol layer which supports offsetting polygons (i.e. simple
fills, raster image fills, shapeburst and gradent fills) now allows
for data-defined offsets
  • Loading branch information
nyalldawson committed Sep 9, 2020
1 parent 014de96 commit 029f067
Show file tree
Hide file tree
Showing 13 changed files with 432 additions and 34 deletions.
87 changes: 83 additions & 4 deletions python/core/auto_generated/symbology/qgsfillsymbollayer.sip.in
Expand Up @@ -79,7 +79,26 @@ Caller takes ownership of the returned symbol layer.
void setPenJoinStyle( Qt::PenJoinStyle style ); void setPenJoinStyle( Qt::PenJoinStyle style );


void setOffset( QPointF offset ); void setOffset( QPointF offset );
%Docstring
Sets an ``offset`` by which polygons will be translated during rendering.

Units are specified by :py:func:`~QgsSimpleFillSymbolLayer.offsetUnit`.

.. seealso:: :py:func:`offset`

.. seealso:: :py:func:`setOffsetUnit`
%End

QPointF offset(); QPointF offset();
%Docstring
Returns the offset by which polygons will be translated during rendering.

Units are specified by :py:func:`~QgsSimpleFillSymbolLayer.offsetUnit`.

.. seealso:: :py:func:`setOffset`

.. seealso:: :py:func:`offsetUnit`
%End


void setStrokeWidthUnit( QgsUnitTypes::RenderUnit unit ); void setStrokeWidthUnit( QgsUnitTypes::RenderUnit unit );
%Docstring %Docstring
Expand All @@ -102,9 +121,9 @@ Returns the units for the width of the fill's stroke.


void setOffsetUnit( QgsUnitTypes::RenderUnit unit ); void setOffsetUnit( QgsUnitTypes::RenderUnit unit );
%Docstring %Docstring
Sets the units for the fill's offset. Sets the ``unit`` for the fill's offset.


:param unit: offset units .. seealso:: :py:func:`offset`


.. seealso:: :py:func:`offsetUnit` .. seealso:: :py:func:`offsetUnit`
%End %End
Expand All @@ -114,10 +133,27 @@ Sets the units for the fill's offset.
Returns the units for the fill's offset. Returns the units for the fill's offset.


.. seealso:: :py:func:`setOffsetUnit` .. seealso:: :py:func:`setOffsetUnit`

.. seealso:: :py:func:`offset`
%End %End


void setOffsetMapUnitScale( const QgsMapUnitScale &scale ); void setOffsetMapUnitScale( const QgsMapUnitScale &scale );
%Docstring
Sets the map unit ``scale`` for the fill's offset.

.. seealso:: :py:func:`setOffset`

.. seealso:: :py:func:`offsetMapUnitScale`
%End

const QgsMapUnitScale &offsetMapUnitScale() const; const QgsMapUnitScale &offsetMapUnitScale() const;
%Docstring
Returns the map unit scale for the fill's offset.

.. seealso:: :py:func:`offset`

.. seealso:: :py:func:`setOffsetMapUnitScale`
%End


virtual void setOutputUnit( QgsUnitTypes::RenderUnit unit ); virtual void setOutputUnit( QgsUnitTypes::RenderUnit unit );


Expand Down Expand Up @@ -304,18 +340,61 @@ Sets the end point of the gradient to be the feature centroid


void setOffset( QPointF offset ); void setOffset( QPointF offset );
%Docstring %Docstring
Offset for gradient fill Sets an ``offset`` by which polygons will be translated during rendering.

Units are specified by :py:func:`~QgsGradientFillSymbolLayer.offsetUnit`.

.. seealso:: :py:func:`offset`

.. seealso:: :py:func:`setOffsetUnit`
%End %End

QPointF offset() const; QPointF offset() const;
%Docstring
Returns the offset by which polygons will be translated during rendering.

Units are specified by :py:func:`~QgsGradientFillSymbolLayer.offsetUnit`.

.. seealso:: :py:func:`setOffset`

.. seealso:: :py:func:`offsetUnit`
%End


void setOffsetUnit( QgsUnitTypes::RenderUnit unit ); void setOffsetUnit( QgsUnitTypes::RenderUnit unit );
%Docstring %Docstring
Units for gradient fill offset Sets the ``unit`` for the fill's offset.

.. seealso:: :py:func:`offset`

.. seealso:: :py:func:`offsetUnit`
%End %End

QgsUnitTypes::RenderUnit offsetUnit() const; QgsUnitTypes::RenderUnit offsetUnit() const;
%Docstring
Returns the units for the fill's offset.

.. seealso:: :py:func:`setOffsetUnit`

.. seealso:: :py:func:`offset`
%End


void setOffsetMapUnitScale( const QgsMapUnitScale &scale ); void setOffsetMapUnitScale( const QgsMapUnitScale &scale );
%Docstring
Sets the map unit ``scale`` for the fill's offset.

.. seealso:: :py:func:`setOffset`

.. seealso:: :py:func:`offsetMapUnitScale`
%End

const QgsMapUnitScale &offsetMapUnitScale() const; const QgsMapUnitScale &offsetMapUnitScale() const;
%Docstring
Returns the map unit scale for the fill's offset.

.. seealso:: :py:func:`offset`

.. seealso:: :py:func:`setOffsetMapUnitScale`
%End


virtual void setOutputUnit( QgsUnitTypes::RenderUnit unit ); virtual void setOutputUnit( QgsUnitTypes::RenderUnit unit );


Expand Down
100 changes: 75 additions & 25 deletions src/core/symbology/qgsfillsymbollayer.cpp
Expand Up @@ -279,11 +279,22 @@ void QgsSimpleFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVe


applyDataDefinedSymbology( context, mBrush, mPen, mSelPen ); applyDataDefinedSymbology( context, mBrush, mPen, mSelPen );


QPointF offset; QPointF offset = mOffset;
if ( !mOffset.isNull() )
if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyOffset ) )
{
context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePoint( mOffset ) );
const QVariant val = mDataDefinedProperties.value( QgsSymbolLayer::PropertyOffset, context.renderContext().expressionContext(), QString() );
bool ok = false;
const QPointF res = QgsSymbolLayerUtils::toPoint( val, &ok );
if ( ok )
offset = res;
}

if ( !offset.isNull() )
{ {
offset.setX( context.renderContext().convertToPainterUnits( mOffset.x(), mOffsetUnit, mOffsetMapUnitScale ) ); offset.setX( context.renderContext().convertToPainterUnits( offset.x(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setY( context.renderContext().convertToPainterUnits( mOffset.y(), mOffsetUnit, mOffsetMapUnitScale ) ); offset.setY( context.renderContext().convertToPainterUnits( offset.y(), mOffsetUnit, mOffsetMapUnitScale ) );
p->translate( offset ); p->translate( offset );
} }


Expand Down Expand Up @@ -311,7 +322,7 @@ void QgsSimpleFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVe
} }
#endif #endif


if ( !mOffset.isNull() ) if ( !offset.isNull() )
{ {
p->translate( -offset ); p->translate( -offset );
} }
Expand Down Expand Up @@ -880,17 +891,27 @@ void QgsGradientFillSymbolLayer::renderPolygon( const QPolygonF &points, const Q
p->setBrush( context.selected() ? mSelBrush : mBrush ); p->setBrush( context.selected() ? mSelBrush : mBrush );
p->setPen( Qt::NoPen ); p->setPen( Qt::NoPen );


QPointF offset; QPointF offset = mOffset;
if ( !mOffset.isNull() ) if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyOffset ) )
{
context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePoint( mOffset ) );
const QVariant val = mDataDefinedProperties.value( QgsSymbolLayer::PropertyOffset, context.renderContext().expressionContext(), QString() );
bool ok = false;
const QPointF res = QgsSymbolLayerUtils::toPoint( val, &ok );
if ( ok )
offset = res;
}

if ( !offset.isNull() )
{ {
offset.setX( context.renderContext().convertToPainterUnits( mOffset.x(), mOffsetUnit, mOffsetMapUnitScale ) ); offset.setX( context.renderContext().convertToPainterUnits( offset.x(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setY( context.renderContext().convertToPainterUnits( mOffset.y(), mOffsetUnit, mOffsetMapUnitScale ) ); offset.setY( context.renderContext().convertToPainterUnits( offset.y(), mOffsetUnit, mOffsetMapUnitScale ) );
p->translate( offset ); p->translate( offset );
} }


_renderPolygon( p, points, rings, context ); _renderPolygon( p, points, rings, context );


if ( !mOffset.isNull() ) if ( !offset.isNull() )
{ {
p->translate( -offset ); p->translate( -offset );
} }
Expand Down Expand Up @@ -1166,15 +1187,26 @@ void QgsShapeburstFillSymbolLayer::renderPolygon( const QPolygonF &points, const
{ {
//feature is selected, draw using selection style //feature is selected, draw using selection style
p->setBrush( mSelBrush ); p->setBrush( mSelBrush );
QPointF offset; QPointF offset = mOffset;
if ( !mOffset.isNull() )
if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyOffset ) )
{ {
offset.setX( context.renderContext().convertToPainterUnits( mOffset.x(), mOffsetUnit, mOffsetMapUnitScale ) ); context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePoint( mOffset ) );
offset.setY( context.renderContext().convertToPainterUnits( mOffset.y(), mOffsetUnit, mOffsetMapUnitScale ) ); const QVariant val = mDataDefinedProperties.value( QgsSymbolLayer::PropertyOffset, context.renderContext().expressionContext(), QString() );
bool ok = false;
const QPointF res = QgsSymbolLayerUtils::toPoint( val, &ok );
if ( ok )
offset = res;
}

if ( !offset.isNull() )
{
offset.setX( context.renderContext().convertToPainterUnits( offset.x(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setY( context.renderContext().convertToPainterUnits( offset.y(), mOffsetUnit, mOffsetMapUnitScale ) );
p->translate( offset ); p->translate( offset );
} }
_renderPolygon( p, points, rings, context ); _renderPolygon( p, points, rings, context );
if ( !mOffset.isNull() ) if ( !offset.isNull() )
{ {
p->translate( -offset ); p->translate( -offset );
} }
Expand Down Expand Up @@ -1298,17 +1330,26 @@ void QgsShapeburstFillSymbolLayer::renderPolygon( const QPolygonF &points, const
//draw shapeburst image in correct place in the destination painter //draw shapeburst image in correct place in the destination painter


QgsScopedQPainterState painterState( p ); QgsScopedQPainterState painterState( p );
QPointF offset; QPointF offset = mOffset;
if ( !mOffset.isNull() ) if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyOffset ) )
{ {
offset.setX( context.renderContext().convertToPainterUnits( mOffset.x(), mOffsetUnit, mOffsetMapUnitScale ) ); context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePoint( mOffset ) );
offset.setY( context.renderContext().convertToPainterUnits( mOffset.y(), mOffsetUnit, mOffsetMapUnitScale ) ); const QVariant val = mDataDefinedProperties.value( QgsSymbolLayer::PropertyOffset, context.renderContext().expressionContext(), QString() );
bool ok = false;
const QPointF res = QgsSymbolLayerUtils::toPoint( val, &ok );
if ( ok )
offset = res;
}
if ( !offset.isNull() )
{
offset.setX( context.renderContext().convertToPainterUnits( offset.x(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setY( context.renderContext().convertToPainterUnits( offset.y(), mOffsetUnit, mOffsetMapUnitScale ) );
p->translate( offset ); p->translate( offset );
} }


p->drawImage( points.boundingRect().left() - sideBuffer, points.boundingRect().top() - sideBuffer, *fillImage ); p->drawImage( points.boundingRect().left() - sideBuffer, points.boundingRect().top() - sideBuffer, *fillImage );


if ( !mOffset.isNull() ) if ( !offset.isNull() )
{ {
p->translate( -offset ); p->translate( -offset );
} }
Expand Down Expand Up @@ -4042,11 +4083,20 @@ void QgsRasterFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVe
return; return;
} }


QPointF offset; QPointF offset = mOffset;
if ( !mOffset.isNull() ) if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyOffset ) )
{
context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePoint( mOffset ) );
const QVariant val = mDataDefinedProperties.value( QgsSymbolLayer::PropertyOffset, context.renderContext().expressionContext(), QString() );
bool ok = false;
const QPointF res = QgsSymbolLayerUtils::toPoint( val, &ok );
if ( ok )
offset = res;
}
if ( !offset.isNull() )
{ {
offset.setX( context.renderContext().convertToPainterUnits( mOffset.x(), mOffsetUnit, mOffsetMapUnitScale ) ); offset.setX( context.renderContext().convertToPainterUnits( offset.x(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setY( context.renderContext().convertToPainterUnits( mOffset.y(), mOffsetUnit, mOffsetMapUnitScale ) ); offset.setY( context.renderContext().convertToPainterUnits( offset.y(), mOffsetUnit, mOffsetMapUnitScale ) );
p->translate( offset ); p->translate( offset );
} }
if ( mCoordinateMode == Feature ) if ( mCoordinateMode == Feature )
Expand All @@ -4057,7 +4107,7 @@ void QgsRasterFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVe
} }


QgsImageFillSymbolLayer::renderPolygon( points, rings, context ); QgsImageFillSymbolLayer::renderPolygon( points, rings, context );
if ( !mOffset.isNull() ) if ( !offset.isNull() )
{ {
p->translate( -offset ); p->translate( -offset );
} }
Expand Down

0 comments on commit 029f067

Please sign in to comment.