Skip to content
Permalink
Browse files

Allow for exact calculation of symbol sizes with mixed layer units

Fixes #21143
  • Loading branch information
nyalldawson committed Feb 4, 2019
1 parent 427cb0b commit 867e39947b3f24d0b7714cd44e28126b61769340
@@ -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;

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

@@ -840,7 +840,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 );
@@ -421,7 +421,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() )
@@ -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() )
{
@@ -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 );
@@ -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 );
}

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

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

@@ -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;
@@ -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 )
@@ -1312,6 +1312,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 )
@@ -1634,6 +1649,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();

0 comments on commit 867e399

Please sign in to comment.
You can’t perform that action at this time.