Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Allow for exact calculation of symbol sizes with mixed layer units
Fixes #21143

(cherry picked from commit 867e399)
  • Loading branch information
nyalldawson committed Feb 7, 2019
1 parent 93c135f commit 33987fa
Show file tree
Hide file tree
Showing 13 changed files with 383 additions and 15 deletions.
Expand Up @@ -223,6 +223,8 @@ Create a new MarkerLineSymbolLayerV2 from SLD

virtual double width() const;

virtual double width( const QgsRenderContext &context ) const;


virtual double estimateMaxBleed( const QgsRenderContext &context ) const;

Expand Down
84 changes: 83 additions & 1 deletion python/core/auto_generated/symbology/qgssymbol.sip.in
Expand Up @@ -687,6 +687,10 @@ Will take ownership.

class QgsMarkerSymbol : QgsSymbol
{
%Docstring

A marker symbol type, for rendering Point and MultiPoint geometries.
%End

%TypeHeaderCode
#include "qgssymbol.h"
Expand All @@ -700,6 +704,11 @@ This is a convenience method for easier creation of marker symbols.
%End

QgsMarkerSymbol( const QgsSymbolLayerList &layers /Transfer/ = QgsSymbolLayerList() );
%Docstring
Constructor for QgsMarkerSymbol, with the specified list of initial symbol ``layers``.

Ownership of the ``layers`` are transferred to the symbol.
%End

void setAngle( double symbolAngle );
%Docstring
Expand Down Expand Up @@ -770,14 +779,37 @@ will be scaled to maintain their current relative size to the whole symbol size.

double size() const;
%Docstring
Returns the size for the whole symbol, which is the maximum size of
Returns the estimated size for the whole symbol, which is the maximum size of
all marker symbol layers in the symbol.

.. warning::

This returned value is inaccurate if the symbol consists of multiple
symbol layers with different size units. Use the overload accepting a :py:class:`QgsRenderContext`
argument instead for accurate sizes in this case.

.. seealso:: :py:func:`setSize`

.. seealso:: :py:func:`sizeUnit`

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

double size( const QgsRenderContext &context ) const;
%Docstring
Returns the symbol size, in painter units. This is the maximum size of
all marker symbol layers in the symbol.

This method returns an accurate size by calculating the actual rendered
size of each symbol layer using the provided render ``context``.

.. seealso:: :py:func:`setSize`

.. seealso:: :py:func:`sizeUnit`

.. seealso:: :py:func:`sizeMapUnitScale`

.. versionadded:: 3.4.5
%End

void setSizeUnit( QgsUnitTypes::RenderUnit unit );
Expand Down Expand Up @@ -890,6 +922,10 @@ and stopRender() calls, or data defined rotation and offset will not be correctl

class QgsLineSymbol : QgsSymbol
{
%Docstring

A line symbol type, for rendering LineString and MultiLineString geometries.
%End

%TypeHeaderCode
#include "qgssymbol.h"
Expand All @@ -903,9 +939,46 @@ This is a convenience method for easier creation of line symbols.
%End

QgsLineSymbol( const QgsSymbolLayerList &layers /Transfer/ = QgsSymbolLayerList() );
%Docstring
Constructor for QgsLineSymbol, with the specified list of initial symbol ``layers``.

Ownership of the ``layers`` are transferred to the symbol.
%End

void setWidth( double width );
%Docstring
Sets the ``width`` for the whole line symbol. Individual symbol layer sizes
will be scaled to maintain their current relative size to the whole symbol size.

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

double width() const;
%Docstring
Returns the estimated width for the whole symbol, which is the maximum width of
all marker symbol layers in the symbol.

.. warning::

This returned value is inaccurate if the symbol consists of multiple
symbol layers with different width units. Use the overload accepting a :py:class:`QgsRenderContext`
argument instead for accurate sizes in this case.

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

double width( const QgsRenderContext &context ) const;
%Docstring
Returns the symbol width, in painter units. This is the maximum width of
all marker symbol layers in the symbol.

This method returns an accurate width by calculating the actual rendered
width of each symbol layer using the provided render ``context``.

.. seealso:: :py:func:`setWidth`

.. versionadded:: 3.4.5
%End

void setDataDefinedWidth( const QgsProperty &property );
%Docstring
Expand Down Expand Up @@ -938,6 +1011,10 @@ Returns data defined width for whole symbol (including all symbol layers).

class QgsFillSymbol : QgsSymbol
{
%Docstring

A fill symbol type, for rendering Polygon and MultiPolygon geometries.
%End

%TypeHeaderCode
#include "qgssymbol.h"
Expand All @@ -951,6 +1028,11 @@ This is a convenience method for easier creation of fill symbols.
%End

QgsFillSymbol( const QgsSymbolLayerList &layers /Transfer/ = QgsSymbolLayerList() );
%Docstring
Constructor for QgsFillSymbol, with the specified list of initial symbol ``layers``.

Ownership of the ``layers`` are transferred to the symbol.
%End
void setAngle( double angle );
void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, const QgsFeature *f, QgsRenderContext &context, int layer = -1, bool selected = false );

Expand Down
24 changes: 24 additions & 0 deletions python/core/auto_generated/symbology/qgssymbollayer.sip.in
Expand Up @@ -835,7 +835,31 @@ class QgsLineSymbolLayer : QgsSymbolLayer
virtual void renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );

virtual void setWidth( double width );

virtual double width() const;
%Docstring
Returns the estimated width for the line symbol layer.

.. warning::

This returned value is inaccurate if the symbol layer has sub-symbols with
different width units. Use the overload accepting a :py:class:`QgsRenderContext`
argument instead for accurate sizes in this case.

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

virtual double width( const QgsRenderContext &context ) const;
%Docstring
Returns the line symbol layer width, in painter units.

This method returns an accurate width by calculating the actual rendered
width of the symbol layer using the provided render ``context``.

.. seealso:: :py:func:`setWidth`

.. versionadded:: 3.4.5
%End

double offset() const;
void setOffset( double offset );
Expand Down
2 changes: 1 addition & 1 deletion src/core/layertree/qgslayertreemodellegendnode.cpp
Expand Up @@ -390,7 +390,7 @@ QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemC
if ( QgsMarkerSymbol *markerSymbol = dynamic_cast<QgsMarkerSymbol *>( s ) )
{
// allow marker symbol to occupy bigger area if necessary
double size = context.convertToPainterUnits( markerSymbol->size(), markerSymbol->sizeUnit(), markerSymbol->sizeMapUnitScale() ) / context.scaleFactor();
double size = markerSymbol->size( context ) / context.scaleFactor();
height = size;
width = size;
if ( width < settings.symbolSize().width() )
Expand Down
10 changes: 8 additions & 2 deletions src/core/symbology/qgslinesymbollayer.cpp
Expand Up @@ -1113,7 +1113,8 @@ void QgsMarkerLineSymbolLayer::renderPolylineVertex( const QPolygonF &points, Qg
|| ( placement == CurvePoint && vId.type == QgsVertexId::CurveVertex ) )
{
//transform
x = vPoint.x(), y = vPoint.y();
x = vPoint.x();
y = vPoint.y();
z = 0.0;
if ( ct.isValid() )
{
Expand Down Expand Up @@ -1618,6 +1619,11 @@ double QgsMarkerLineSymbolLayer::width() const
return mMarker->size();
}

double QgsMarkerLineSymbolLayer::width( const QgsRenderContext &context ) const
{
return mMarker->size( context );
}

void QgsMarkerLineSymbolLayer::setOutputUnit( QgsUnitTypes::RenderUnit unit )
{
QgsLineSymbolLayer::setOutputUnit( unit );
Expand Down Expand Up @@ -1675,7 +1681,7 @@ bool QgsMarkerLineSymbolLayer::hasDataDefinedProperties() const

double QgsMarkerLineSymbolLayer::estimateMaxBleed( const QgsRenderContext &context ) const
{
return context.convertToPainterUnits( ( mMarker->size() / 2.0 ), mMarker->sizeUnit(), mMarker->sizeMapUnitScale() ) +
return ( mMarker->size( context ) / 2.0 ) +
context.convertToPainterUnits( std::fabs( mOffset ), mOffsetUnit, mOffsetMapUnitScale );
}

Expand Down
1 change: 1 addition & 0 deletions src/core/symbology/qgslinesymbollayer.h
Expand Up @@ -234,6 +234,7 @@ class CORE_EXPORT QgsMarkerLineSymbolLayer : public QgsLineSymbolLayer

void setWidth( double width ) override;
double width() const override;
double width( const QgsRenderContext &context ) const override;

double estimateMaxBleed( const QgsRenderContext &context ) const override;

Expand Down
11 changes: 4 additions & 7 deletions src/core/symbology/qgspointdisplacementrenderer.cpp
Expand Up @@ -61,12 +61,11 @@ void QgsPointDisplacementRenderer::drawGroup( QPointF centerPoint, QgsRenderCont
//calculate max diagonal size from all symbols in group
double diagonal = 0;

Q_FOREACH ( const GroupedFeature &feature, group )
for ( const GroupedFeature &feature : group )
{
if ( QgsMarkerSymbol *symbol = feature.symbol() )
{
diagonal = std::max( diagonal, context.convertToPainterUnits( M_SQRT2 * symbol->size(),
symbol->sizeUnit(), symbol->sizeMapUnitScale() ) );
diagonal = std::max( diagonal, M_SQRT2 * symbol->size( context ) );
}
}

Expand Down Expand Up @@ -274,8 +273,7 @@ void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRe
}
case ConcentricRings:
{
double centerDiagonal = symbolContext.renderContext().convertToPainterUnits( M_SQRT2 * mCenterSymbol->size(),
mCenterSymbol->sizeUnit(), mCenterSymbol->sizeMapUnitScale() );
double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2;

int pointsRemaining = nPosition;
int ringNumber = 1;
Expand Down Expand Up @@ -307,8 +305,7 @@ void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRe
}
case Grid:
{
double centerDiagonal = symbolContext.renderContext().convertToPainterUnits( M_SQRT2 * mCenterSymbol->size(),
mCenterSymbol->sizeUnit(), mCenterSymbol->sizeMapUnitScale() );
double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2;
int pointsRemaining = nPosition;
gridSize = std::ceil( std::sqrt( pointsRemaining ) );
if ( pointsRemaining - std::pow( gridSize - 1, 2 ) < gridSize )
Expand Down
30 changes: 30 additions & 0 deletions src/core/symbology/qgssymbol.cpp
Expand Up @@ -1303,6 +1303,21 @@ double QgsMarkerSymbol::size() const
return maxSize;
}

double QgsMarkerSymbol::size( const QgsRenderContext &context ) const
{
// return size of the largest symbol
double maxSize = 0;
for ( QgsSymbolLayer *layer : mLayers )
{
if ( layer->type() != QgsSymbol::Marker )
continue;
const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
const double layerSize = context.convertToPainterUnits( markerLayer->size(), markerLayer->sizeUnit(), markerLayer->sizeMapUnitScale() );
maxSize = std::max( maxSize, layerSize );
}
return maxSize;
}

void QgsMarkerSymbol::setSizeUnit( QgsUnitTypes::RenderUnit unit )
{
Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
Expand Down Expand Up @@ -1625,6 +1640,21 @@ double QgsLineSymbol::width() const
return maxWidth;
}

double QgsLineSymbol::width( const QgsRenderContext &context ) const
{
// return width of the largest symbol
double maxWidth = 0;
for ( QgsSymbolLayer *layer : mLayers )
{
if ( layer->type() != QgsSymbol::Line )
continue;
const QgsLineSymbolLayer *lineLayer = static_cast<const QgsLineSymbolLayer *>( layer );
const double layerWidth = lineLayer->width( context );
maxWidth = std::max( maxWidth, layerWidth );
}
return maxWidth;
}

void QgsLineSymbol::setDataDefinedWidth( const QgsProperty &property )
{
const double symbolWidth = width();
Expand Down

0 comments on commit 33987fa

Please sign in to comment.