Skip to content
Permalink
Browse files
[FEATURE][symbology] Add coordinate reference mode (i.e. pattern alig…
…nment) to line pattern and point pattern symbol layer types
  • Loading branch information
nirvn committed Oct 23, 2021
1 parent 835f6d3 commit 6a37ee72fadda1d2d66e4e20feabd08a320c59eb
@@ -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 );
@@ -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;


@@ -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.

@@ -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;

};

@@ -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.
@@ -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() )
{
@@ -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 );
@@ -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;
}


@@ -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 );

@@ -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 ) );
@@ -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 );

@@ -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 );
@@ -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 ) );
@@ -4224,6 +4265,7 @@ QgsRasterFillSymbolLayer::QgsRasterFillSymbolLayer( const QString &imageFilePath
, mImageFilePath( imageFilePath )
{
QgsImageFillSymbolLayer::setSubSymbol( nullptr ); //disable sub symbol
mCoordinateReference = Qgis::SymbolCoordinateReference::Viewport;
}

QgsRasterFillSymbolLayer::~QgsRasterFillSymbolLayer() = default;
@@ -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;
}
@@ -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;
@@ -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
@@ -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
@@ -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
@@ -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 )
@@ -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

0 comments on commit 6a37ee7

Please sign in to comment.