Skip to content

Commit

Permalink
Avoid texture jump when panning maps
Browse files Browse the repository at this point in the history
We don't need the whole expense of the "Avoid artifacts when rendering as map tiles"
option, because that disables to default clipping of geometry parts which fall
outside the visible canvas extent and accordingly results in a lot of wasted rendering
calculations. Instead, we can just always use the upper left corner of the original
feature geometry before the optimisations like clipping to visible regions are applied,
and use this as the texture origin.

This means we can safely make this handling always applied and not an opt-in setting
  • Loading branch information
nyalldawson committed Jul 11, 2020
1 parent 81518f9 commit 28c8eef
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 1 deletion.
20 changes: 20 additions & 0 deletions python/core/auto_generated/qgsrendercontext.sip.in
Expand Up @@ -841,6 +841,26 @@ Sets a ``geometry`` to use to clip features at render time.

.. seealso:: :py:func:`featureClipGeometry`

.. versionadded:: 3.16
%End

QPointF textureOrigin() const;
%Docstring
Returns the texture origin, which should be used as a brush transform when
rendering using QBrush objects.

.. seealso:: :py:func:`setTextureOrigin`

.. versionadded:: 3.16
%End

void setTextureOrigin( const QPointF &origin );
%Docstring
Sets the texture ``origin``, which should be used as a brush transform when
rendering using QBrush objects.

.. seealso:: :py:func:`textureOrigin`

.. versionadded:: 3.16
%End

Expand Down
12 changes: 12 additions & 0 deletions src/core/qgsrendercontext.cpp
Expand Up @@ -69,6 +69,7 @@ QgsRenderContext::QgsRenderContext( const QgsRenderContext &rh )
, mDisabledSymbolLayers()
, mClippingRegions( rh.mClippingRegions )
, mFeatureClipGeometry( rh.mFeatureClipGeometry )
, mTextureOrigin( rh.mTextureOrigin )
#ifdef QGISDEBUG
, mHasTransformContext( rh.mHasTransformContext )
#endif
Expand Down Expand Up @@ -104,6 +105,7 @@ QgsRenderContext &QgsRenderContext::operator=( const QgsRenderContext &rh )
mCustomRenderingFlags = rh.mCustomRenderingFlags;
mClippingRegions = rh.mClippingRegions;
mFeatureClipGeometry = rh.mFeatureClipGeometry;
mTextureOrigin = rh.mTextureOrigin;
setIsTemporal( rh.isTemporal() );
if ( isTemporal() )
setTemporalRange( rh.temporalRange() );
Expand Down Expand Up @@ -534,4 +536,14 @@ void QgsRenderContext::setFeatureClipGeometry( const QgsGeometry &geometry )
mFeatureClipGeometry = geometry;
}

QPointF QgsRenderContext::textureOrigin() const
{
return mTextureOrigin;
}

void QgsRenderContext::setTextureOrigin( const QPointF &origin )
{
mTextureOrigin = origin;
}


20 changes: 20 additions & 0 deletions src/core/qgsrendercontext.h
Expand Up @@ -836,6 +836,24 @@ class CORE_EXPORT QgsRenderContext : public QgsTemporalRangeObject
*/
void setFeatureClipGeometry( const QgsGeometry &geometry );

/**
* Returns the texture origin, which should be used as a brush transform when
* rendering using QBrush objects.
*
* \see setTextureOrigin()
* \since QGIS 3.16
*/
QPointF textureOrigin() const;

/**
* Sets the texture \a origin, which should be used as a brush transform when
* rendering using QBrush objects.
*
* \see textureOrigin()
* \since QGIS 3.16
*/
void setTextureOrigin( const QPointF &origin );

private:

Flags mFlags;
Expand Down Expand Up @@ -930,6 +948,8 @@ class CORE_EXPORT QgsRenderContext : public QgsTemporalRangeObject
QList< QgsMapClippingRegion > mClippingRegions;
QgsGeometry mFeatureClipGeometry;

QPointF mTextureOrigin;

#ifdef QGISDEBUG
bool mHasTransformContext = false;
#endif
Expand Down
9 changes: 8 additions & 1 deletion src/core/symbology/qgsfillsymbollayer.cpp
Expand Up @@ -1597,7 +1597,14 @@ void QgsImageFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVec
p->setPen( QPen( Qt::NoPen ) );

QTransform bkTransform = mBrush.transform();
if ( context.renderContext().testFlag( QgsRenderContext::RenderMapTile ) )
if ( !context.renderContext().textureOrigin().isNull() )
{
QPointF leftCorner = context.renderContext().textureOrigin();
QTransform t = mBrush.transform();
t.translate( leftCorner.x(), leftCorner.y() );
mBrush.setTransform( t );
}
else if ( context.renderContext().testFlag( QgsRenderContext::RenderMapTile ) )
{
//transform brush to upper left corner of geometry bbox
QPointF leftCorner = points.boundingRect().topLeft();
Expand Down
6 changes: 6 additions & 0 deletions src/core/symbology/qgssymbol.cpp
Expand Up @@ -832,6 +832,12 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
bool usingSegmentizedGeometry = false;
context.setGeometry( geom.constGet() );

if ( !geom.boundingBox().isNull() )
{
const QPointF boundsOrigin = _getPoint( context, QgsPoint( geom.boundingBox().xMinimum(), geom.boundingBox().yMinimum() ) );
context.setTextureOrigin( boundsOrigin );
}

bool tileMapRendering = context.testFlag( QgsRenderContext::RenderMapTile );

//convert curve types to normal point/line/polygon ones
Expand Down

0 comments on commit 28c8eef

Please sign in to comment.