Skip to content

Commit

Permalink
[FEATURE][symbology] Add coordinate reference mode (i.e. pattern alig…
Browse files Browse the repository at this point in the history
…nment) to line pattern and point pattern symbol layer types
  • Loading branch information
nirvn committed Oct 23, 2021
1 parent 835f6d3 commit 6a37ee7
Show file tree
Hide file tree
Showing 15 changed files with 386 additions and 59 deletions.
30 changes: 28 additions & 2 deletions python/core/auto_generated/symbology/qgsfillsymbollayer.sip.in
Expand Up @@ -859,6 +859,30 @@ Returns the stroke width map unit scale.
.. seealso:: :py:func:`strokeWidthUnit`

.. versionadded:: 2.16
%End

void setCoordinateReference( Qgis::SymbolCoordinateReference coordinateReference );
%Docstring
Sets the coordinate reference mode for fill which controls how the top left corner of the image
fill is positioned relative to the feature.

:param coordinateReference: coordinate reference mode

.. seealso:: :py:func:`coordinateReference`

.. versionadded:: 3.24
%End

Qgis::SymbolCoordinateReference coordinateReference() const;
%Docstring
Returns the coordinate reference mode for fill which controls how the top left corner of the image
fill is positioned relative to the feature.

:return: coordinate reference mode

.. seealso:: :py:func:`setCoordinateReference`

.. versionadded:: 3.24
%End

virtual void setOutputUnit( QgsUnitTypes::RenderUnit unit );
Expand All @@ -879,6 +903,8 @@ Returns the stroke width map unit scale.

virtual QSet<QString> usedAttributes( const QgsRenderContext &context ) const;

virtual QVariantMap properties() const;

virtual bool hasDataDefinedProperties() const;


Expand All @@ -891,7 +917,7 @@ Returns the stroke width map unit scale.
Custom stroke
%End

virtual bool applyBrushTransformFromContext() const;
virtual bool applyBrushTransformFromContext( QgsSymbolRenderContext *context = 0 ) const;
%Docstring
Returns ``True`` if the image brush should be transformed using the render context's texture origin.

Expand Down Expand Up @@ -1176,7 +1202,7 @@ Returns the map unit scale for the image's width.

virtual void applyDataDefinedSettings( QgsSymbolRenderContext &context );

virtual bool applyBrushTransformFromContext() const;
virtual bool applyBrushTransformFromContext( QgsSymbolRenderContext *context = 0 ) const;

};

Expand Down
25 changes: 25 additions & 0 deletions python/core/auto_generated/symbology/qgssymbollayerutils.sip.in
Expand Up @@ -56,6 +56,31 @@ class QgsSymbolLayerUtils
static QString encodeSldBrushStyle( Qt::BrushStyle style );
static Qt::BrushStyle decodeSldBrushStyle( const QString &str );

static Qgis::SymbolCoordinateReference decodeCoordinateReference( const QString &string, bool *ok /Out/ = 0 );
%Docstring
Decodes a ``string`` representing a symbol coordinate reference mode.

:param string: string to decode

:return: - decoded marker clip mode
- ok: will be set to ``True`` if ``string`` was successfully decoded

.. seealso:: :py:func:`encodeCoordinateReference`

.. versionadded:: 3.24
%End

static QString encodeCoordinateReference( Qgis::SymbolCoordinateReference coordinateReference );
%Docstring
Encodes a symbol coordinate reference mode to a string.

:param coordinateReference: coordinate reference mode

.. seealso:: :py:func:`decodeCoordinateReference`

.. versionadded:: 3.24
%End

static QgsArrowSymbolLayer::HeadType decodeArrowHeadType( const QVariant &value, bool *ok /Out/ = 0 );
%Docstring
Decodes a ``value`` representing an arrow head type.
Expand Down
62 changes: 52 additions & 10 deletions src/core/symbology/qgsfillsymbollayer.cpp
Expand Up @@ -1721,13 +1721,19 @@ void QgsImageFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVec
p->setPen( QPen( Qt::NoPen ) );

QTransform bkTransform = mBrush.transform();
if ( applyBrushTransformFromContext() && !context.renderContext().textureOrigin().isNull() )
if ( applyBrushTransformFromContext( &context ) && !context.renderContext().textureOrigin().isNull() )
{
QPointF leftCorner = context.renderContext().textureOrigin();
QTransform t = mBrush.transform();
t.translate( leftCorner.x(), leftCorner.y() );
mBrush.setTransform( t );
}
else
{
QTransform t = mBrush.transform();
t.translate( 0, 0 );
mBrush.setTransform( t );
}

if ( context.selected() )
{
Expand Down Expand Up @@ -1855,6 +1861,13 @@ Qt::PenStyle QgsImageFillSymbolLayer::dxfPenStyle() const
#endif //0
}

QVariantMap QgsImageFillSymbolLayer::properties() const
{
QVariantMap map;
map.insert( QStringLiteral( "coordinate_reference" ), QgsSymbolLayerUtils::encodeCoordinateReference( mCoordinateReference ) );
return map;
}

QSet<QString> QgsImageFillSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
{
QSet<QString> attr = QgsFillSymbolLayer::usedAttributes( context );
Expand All @@ -1872,9 +1885,23 @@ bool QgsImageFillSymbolLayer::hasDataDefinedProperties() const
return false;
}

bool QgsImageFillSymbolLayer::applyBrushTransformFromContext() const
bool QgsImageFillSymbolLayer::applyBrushTransformFromContext( QgsSymbolRenderContext *context ) const
{
return true;
//coordinate reference
Qgis::SymbolCoordinateReference coordinateReference = mCoordinateReference;
if ( context && mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyCoordinateMode ) )
{
bool ok = false;
QString string = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyCoordinateMode, context->renderContext().expressionContext(), QString(), &ok );
if ( ok )
{
coordinateReference = QgsSymbolLayerUtils::decodeCoordinateReference( string, &ok );
if ( !ok )
coordinateReference = mCoordinateReference;
}
}

return coordinateReference == Qgis::SymbolCoordinateReference::Feature;
}


Expand Down Expand Up @@ -2680,6 +2707,10 @@ QgsSymbolLayer *QgsLinePatternFillSymbolLayer::create( const QVariantMap &proper
{
patternLayer->setStrokeWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "outline_width_map_unit_scale" )].toString() ) );
}
if ( properties.contains( QStringLiteral( "coordinate_reference" ) ) )
{
patternLayer->setCoordinateReference( QgsSymbolLayerUtils::decodeCoordinateReference( properties[QStringLiteral( "coordinate_reference" )].toString() ) );
}

patternLayer->restoreOldDataDefinedProperties( properties );

Expand Down Expand Up @@ -2998,7 +3029,7 @@ void QgsLinePatternFillSymbolLayer::stopRender( QgsSymbolRenderContext &context

QVariantMap QgsLinePatternFillSymbolLayer::properties() const
{
QVariantMap map;
QVariantMap map = QgsImageFillSymbolLayer::properties();
map.insert( QStringLiteral( "angle" ), QString::number( mLineAngle ) );
map.insert( QStringLiteral( "distance" ), QString::number( mDistance ) );
map.insert( QStringLiteral( "line_width" ), QString::number( mLineWidth ) );
Expand Down Expand Up @@ -3342,6 +3373,10 @@ QgsSymbolLayer *QgsPointPatternFillSymbolLayer::create( const QVariantMap &prope
{
layer->setClipMode( QgsSymbolLayerUtils::decodeMarkerClipMode( properties.value( QStringLiteral( "clip_mode" ) ).toString() ) );
}
if ( properties.contains( QStringLiteral( "coordinate_reference" ) ) )
{
layer->setCoordinateReference( QgsSymbolLayerUtils::decodeCoordinateReference( properties[QStringLiteral( "coordinate_reference" )].toString() ) );
}

layer->restoreOldDataDefinedProperties( properties );

Expand Down Expand Up @@ -3614,10 +3649,16 @@ void QgsPointPatternFillSymbolLayer::renderPolygon( const QPolygonF &points, con
}
}

const double left = points.boundingRect().left() - 2 * width;
const double top = points.boundingRect().top() - 2 * height;
const double right = points.boundingRect().right() + 2 * width;
const double bottom = points.boundingRect().bottom() + 2 * height;
const QRectF boundingRect = points.boundingRect();
double left = boundingRect.left() - 2 * width;
double top = boundingRect.top() - 2 * height;
const double right = boundingRect.right() + 2 * width;
const double bottom = boundingRect.bottom() + 2 * height;
if ( !applyBrushTransformFromContext( &context ) )
{
left -= boundingRect.left() - ( width * std::floor( boundingRect.left() / width ) );
top -= boundingRect.top() - ( height * std::floor( boundingRect.top() / height ) );
}

QgsExpressionContextScope *scope = new QgsExpressionContextScope();
QgsExpressionContextScopePopper scopePopper( context.renderContext().expressionContext(), scope );
Expand Down Expand Up @@ -3705,7 +3746,7 @@ void QgsPointPatternFillSymbolLayer::renderPolygon( const QPolygonF &points, con

QVariantMap QgsPointPatternFillSymbolLayer::properties() const
{
QVariantMap map;
QVariantMap map = QgsImageFillSymbolLayer::properties();
map.insert( QStringLiteral( "distance_x" ), QString::number( mDistanceX ) );
map.insert( QStringLiteral( "distance_y" ), QString::number( mDistanceY ) );
map.insert( QStringLiteral( "displacement_x" ), QString::number( mDisplacementX ) );
Expand Down Expand Up @@ -4224,6 +4265,7 @@ QgsRasterFillSymbolLayer::QgsRasterFillSymbolLayer( const QString &imageFilePath
, mImageFilePath( imageFilePath )
{
QgsImageFillSymbolLayer::setSubSymbol( nullptr ); //disable sub symbol
mCoordinateReference = Qgis::SymbolCoordinateReference::Viewport;
}

QgsRasterFillSymbolLayer::~QgsRasterFillSymbolLayer() = default;
Expand Down Expand Up @@ -4469,7 +4511,7 @@ void QgsRasterFillSymbolLayer::applyDataDefinedSettings( QgsSymbolRenderContext
applyPattern( mBrush, file, width, opacity, context );
}

bool QgsRasterFillSymbolLayer::applyBrushTransformFromContext() const
bool QgsRasterFillSymbolLayer::applyBrushTransformFromContext( QgsSymbolRenderContext * ) const
{
return false;
}
Expand Down
24 changes: 22 additions & 2 deletions src/core/symbology/qgsfillsymbollayer.h
Expand Up @@ -818,6 +818,24 @@ class CORE_EXPORT QgsImageFillSymbolLayer: public QgsFillSymbolLayer
*/
const QgsMapUnitScale &strokeWidthMapUnitScale() const { return mStrokeWidthMapUnitScale; }

/**
* Sets the coordinate reference mode for fill which controls how the top left corner of the image
* fill is positioned relative to the feature.
* \param coordinateReference coordinate reference mode
* \see coordinateReference
* \since QGIS 3.24
*/
void setCoordinateReference( Qgis::SymbolCoordinateReference coordinateReference ) { mCoordinateReference = coordinateReference; }

/**
* Returns the coordinate reference mode for fill which controls how the top left corner of the image
* fill is positioned relative to the feature.
* \returns coordinate reference mode
* \see setCoordinateReference
* \since QGIS 3.24
*/
Qgis::SymbolCoordinateReference coordinateReference() const { return mCoordinateReference; }

void setOutputUnit( QgsUnitTypes::RenderUnit unit ) override;
QgsUnitTypes::RenderUnit outputUnit() const override;
void setMapUnitScale( const QgsMapUnitScale &scale ) override;
Expand All @@ -827,10 +845,12 @@ class CORE_EXPORT QgsImageFillSymbolLayer: public QgsFillSymbolLayer
QColor dxfColor( QgsSymbolRenderContext &context ) const override;
Qt::PenStyle dxfPenStyle() const override;
QSet<QString> usedAttributes( const QgsRenderContext &context ) const override;
QVariantMap properties() const override;
bool hasDataDefinedProperties() const override;

protected:
QBrush mBrush;
Qgis::SymbolCoordinateReference mCoordinateReference = Qgis::SymbolCoordinateReference::Feature;
double mNextAngle = 0.0; // mAngle / data defined angle

//! Stroke width
Expand All @@ -848,7 +868,7 @@ class CORE_EXPORT QgsImageFillSymbolLayer: public QgsFillSymbolLayer
*
* \since QGIS 3.16
*/
virtual bool applyBrushTransformFromContext() const;
virtual bool applyBrushTransformFromContext( QgsSymbolRenderContext *context = nullptr ) const;

private:
#ifdef SIP_RUN
Expand Down Expand Up @@ -1058,7 +1078,7 @@ class CORE_EXPORT QgsRasterFillSymbolLayer: public QgsImageFillSymbolLayer
protected:

void applyDataDefinedSettings( QgsSymbolRenderContext &context ) override;
bool applyBrushTransformFromContext() const override;
bool applyBrushTransformFromContext( QgsSymbolRenderContext *context = nullptr ) const override;
private:

//! Path to the image file
Expand Down
28 changes: 28 additions & 0 deletions src/core/symbology/qgssymbollayerutils.cpp
Expand Up @@ -387,6 +387,34 @@ Qt::BrushStyle QgsSymbolLayerUtils::decodeSldBrushStyle( const QString &str )
return Qt::NoBrush;
}

Qgis::SymbolCoordinateReference QgsSymbolLayerUtils::decodeCoordinateReference( const QString &string, bool *ok )
{
const QString compareString = string.trimmed();
if ( ok )
*ok = true;

if ( compareString.compare( QLatin1String( "feature" ), Qt::CaseInsensitive ) == 0 )
return Qgis::SymbolCoordinateReference::Feature;
else if ( compareString.compare( QLatin1String( "viewport" ), Qt::CaseInsensitive ) == 0 )
return Qgis::SymbolCoordinateReference::Viewport;

if ( ok )
*ok = false;
return Qgis::SymbolCoordinateReference::Feature;
}

QString QgsSymbolLayerUtils::encodeCoordinateReference( Qgis::SymbolCoordinateReference coordinateReference )
{
switch ( coordinateReference )
{
case Qgis::SymbolCoordinateReference::Feature:
return QStringLiteral( "feature" );
case Qgis::SymbolCoordinateReference::Viewport:
return QStringLiteral( "viewport" );
}
return QString(); // no warnings
}

QgsArrowSymbolLayer::HeadType QgsSymbolLayerUtils::decodeArrowHeadType( const QVariant &value, bool *ok )
{
if ( ok )
Expand Down
21 changes: 21 additions & 0 deletions src/core/symbology/qgssymbollayerutils.h
Expand Up @@ -91,6 +91,27 @@ class CORE_EXPORT QgsSymbolLayerUtils
static QString encodeSldBrushStyle( Qt::BrushStyle style );
static Qt::BrushStyle decodeSldBrushStyle( const QString &str );

/**
* Decodes a \a string representing a symbol coordinate reference mode.
*
* \param string string to decode
* \param ok will be set to TRUE if \a string was successfully decoded
* \returns decoded marker clip mode
*
* \see encodeCoordinateReference()
* \since QGIS 3.24
*/
static Qgis::SymbolCoordinateReference decodeCoordinateReference( const QString &string, bool *ok SIP_OUT = nullptr );

/**
* Encodes a symbol coordinate reference mode to a string.
*
* \param coordinateReference coordinate reference mode
* \see decodeCoordinateReference()
* \since QGIS 3.24
*/
static QString encodeCoordinateReference( Qgis::SymbolCoordinateReference coordinateReference );

/**
* Decodes a \a value representing an arrow head type.
* \since QGIS 3.2
Expand Down

0 comments on commit 6a37ee7

Please sign in to comment.