Skip to content

Commit 33987fa

Browse files
committed
Allow for exact calculation of symbol sizes with mixed layer units
Fixes #21143 (cherry picked from commit 867e399)
1 parent 93c135f commit 33987fa

13 files changed

+383
-15
lines changed

python/core/auto_generated/symbology/qgslinesymbollayer.sip.in

+2
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ Create a new MarkerLineSymbolLayerV2 from SLD
223223

224224
virtual double width() const;
225225

226+
virtual double width( const QgsRenderContext &context ) const;
227+
226228

227229
virtual double estimateMaxBleed( const QgsRenderContext &context ) const;
228230

python/core/auto_generated/symbology/qgssymbol.sip.in

+83-1
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,10 @@ Will take ownership.
687687

688688
class QgsMarkerSymbol : QgsSymbol
689689
{
690+
%Docstring
691+
692+
A marker symbol type, for rendering Point and MultiPoint geometries.
693+
%End
690694

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

702706
QgsMarkerSymbol( const QgsSymbolLayerList &layers /Transfer/ = QgsSymbolLayerList() );
707+
%Docstring
708+
Constructor for QgsMarkerSymbol, with the specified list of initial symbol ``layers``.
709+
710+
Ownership of the ``layers`` are transferred to the symbol.
711+
%End
703712

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

771780
double size() const;
772781
%Docstring
773-
Returns the size for the whole symbol, which is the maximum size of
782+
Returns the estimated size for the whole symbol, which is the maximum size of
774783
all marker symbol layers in the symbol.
775784

785+
.. warning::
786+
787+
This returned value is inaccurate if the symbol consists of multiple
788+
symbol layers with different size units. Use the overload accepting a :py:class:`QgsRenderContext`
789+
argument instead for accurate sizes in this case.
790+
776791
.. seealso:: :py:func:`setSize`
777792

778793
.. seealso:: :py:func:`sizeUnit`
779794

780795
.. seealso:: :py:func:`sizeMapUnitScale`
796+
%End
797+
798+
double size( const QgsRenderContext &context ) const;
799+
%Docstring
800+
Returns the symbol size, in painter units. This is the maximum size of
801+
all marker symbol layers in the symbol.
802+
803+
This method returns an accurate size by calculating the actual rendered
804+
size of each symbol layer using the provided render ``context``.
805+
806+
.. seealso:: :py:func:`setSize`
807+
808+
.. seealso:: :py:func:`sizeUnit`
809+
810+
.. seealso:: :py:func:`sizeMapUnitScale`
811+
812+
.. versionadded:: 3.4.5
781813
%End
782814

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

891923
class QgsLineSymbol : QgsSymbol
892924
{
925+
%Docstring
926+
927+
A line symbol type, for rendering LineString and MultiLineString geometries.
928+
%End
893929

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

905941
QgsLineSymbol( const QgsSymbolLayerList &layers /Transfer/ = QgsSymbolLayerList() );
942+
%Docstring
943+
Constructor for QgsLineSymbol, with the specified list of initial symbol ``layers``.
944+
945+
Ownership of the ``layers`` are transferred to the symbol.
946+
%End
906947

907948
void setWidth( double width );
949+
%Docstring
950+
Sets the ``width`` for the whole line symbol. Individual symbol layer sizes
951+
will be scaled to maintain their current relative size to the whole symbol size.
952+
953+
.. seealso:: :py:func:`width`
954+
%End
955+
908956
double width() const;
957+
%Docstring
958+
Returns the estimated width for the whole symbol, which is the maximum width of
959+
all marker symbol layers in the symbol.
960+
961+
.. warning::
962+
963+
This returned value is inaccurate if the symbol consists of multiple
964+
symbol layers with different width units. Use the overload accepting a :py:class:`QgsRenderContext`
965+
argument instead for accurate sizes in this case.
966+
967+
.. seealso:: :py:func:`setWidth`
968+
%End
969+
970+
double width( const QgsRenderContext &context ) const;
971+
%Docstring
972+
Returns the symbol width, in painter units. This is the maximum width of
973+
all marker symbol layers in the symbol.
974+
975+
This method returns an accurate width by calculating the actual rendered
976+
width of each symbol layer using the provided render ``context``.
977+
978+
.. seealso:: :py:func:`setWidth`
979+
980+
.. versionadded:: 3.4.5
981+
%End
909982

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

9391012
class QgsFillSymbol : QgsSymbol
9401013
{
1014+
%Docstring
1015+
1016+
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
1017+
%End
9411018

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

9531030
QgsFillSymbol( const QgsSymbolLayerList &layers /Transfer/ = QgsSymbolLayerList() );
1031+
%Docstring
1032+
Constructor for QgsFillSymbol, with the specified list of initial symbol ``layers``.
1033+
1034+
Ownership of the ``layers`` are transferred to the symbol.
1035+
%End
9541036
void setAngle( double angle );
9551037
void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, const QgsFeature *f, QgsRenderContext &context, int layer = -1, bool selected = false );
9561038

python/core/auto_generated/symbology/qgssymbollayer.sip.in

+24
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,31 @@ class QgsLineSymbolLayer : QgsSymbolLayer
835835
virtual void renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
836836

837837
virtual void setWidth( double width );
838+
838839
virtual double width() const;
840+
%Docstring
841+
Returns the estimated width for the line symbol layer.
842+
843+
.. warning::
844+
845+
This returned value is inaccurate if the symbol layer has sub-symbols with
846+
different width units. Use the overload accepting a :py:class:`QgsRenderContext`
847+
argument instead for accurate sizes in this case.
848+
849+
.. seealso:: :py:func:`setWidth`
850+
%End
851+
852+
virtual double width( const QgsRenderContext &context ) const;
853+
%Docstring
854+
Returns the line symbol layer width, in painter units.
855+
856+
This method returns an accurate width by calculating the actual rendered
857+
width of the symbol layer using the provided render ``context``.
858+
859+
.. seealso:: :py:func:`setWidth`
860+
861+
.. versionadded:: 3.4.5
862+
%End
839863

840864
double offset() const;
841865
void setOffset( double offset );

src/core/layertree/qgslayertreemodellegendnode.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemC
390390
if ( QgsMarkerSymbol *markerSymbol = dynamic_cast<QgsMarkerSymbol *>( s ) )
391391
{
392392
// allow marker symbol to occupy bigger area if necessary
393-
double size = context.convertToPainterUnits( markerSymbol->size(), markerSymbol->sizeUnit(), markerSymbol->sizeMapUnitScale() ) / context.scaleFactor();
393+
double size = markerSymbol->size( context ) / context.scaleFactor();
394394
height = size;
395395
width = size;
396396
if ( width < settings.symbolSize().width() )

src/core/symbology/qgslinesymbollayer.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -1113,7 +1113,8 @@ void QgsMarkerLineSymbolLayer::renderPolylineVertex( const QPolygonF &points, Qg
11131113
|| ( placement == CurvePoint && vId.type == QgsVertexId::CurveVertex ) )
11141114
{
11151115
//transform
1116-
x = vPoint.x(), y = vPoint.y();
1116+
x = vPoint.x();
1117+
y = vPoint.y();
11171118
z = 0.0;
11181119
if ( ct.isValid() )
11191120
{
@@ -1618,6 +1619,11 @@ double QgsMarkerLineSymbolLayer::width() const
16181619
return mMarker->size();
16191620
}
16201621

1622+
double QgsMarkerLineSymbolLayer::width( const QgsRenderContext &context ) const
1623+
{
1624+
return mMarker->size( context );
1625+
}
1626+
16211627
void QgsMarkerLineSymbolLayer::setOutputUnit( QgsUnitTypes::RenderUnit unit )
16221628
{
16231629
QgsLineSymbolLayer::setOutputUnit( unit );
@@ -1675,7 +1681,7 @@ bool QgsMarkerLineSymbolLayer::hasDataDefinedProperties() const
16751681

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

src/core/symbology/qgslinesymbollayer.h

+1
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ class CORE_EXPORT QgsMarkerLineSymbolLayer : public QgsLineSymbolLayer
234234

235235
void setWidth( double width ) override;
236236
double width() const override;
237+
double width( const QgsRenderContext &context ) const override;
237238

238239
double estimateMaxBleed( const QgsRenderContext &context ) const override;
239240

src/core/symbology/qgspointdisplacementrenderer.cpp

+4-7
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,11 @@ void QgsPointDisplacementRenderer::drawGroup( QPointF centerPoint, QgsRenderCont
6161
//calculate max diagonal size from all symbols in group
6262
double diagonal = 0;
6363

64-
Q_FOREACH ( const GroupedFeature &feature, group )
64+
for ( const GroupedFeature &feature : group )
6565
{
6666
if ( QgsMarkerSymbol *symbol = feature.symbol() )
6767
{
68-
diagonal = std::max( diagonal, context.convertToPainterUnits( M_SQRT2 * symbol->size(),
69-
symbol->sizeUnit(), symbol->sizeMapUnitScale() ) );
68+
diagonal = std::max( diagonal, M_SQRT2 * symbol->size( context ) );
7069
}
7170
}
7271

@@ -274,8 +273,7 @@ void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRe
274273
}
275274
case ConcentricRings:
276275
{
277-
double centerDiagonal = symbolContext.renderContext().convertToPainterUnits( M_SQRT2 * mCenterSymbol->size(),
278-
mCenterSymbol->sizeUnit(), mCenterSymbol->sizeMapUnitScale() );
276+
double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2;
279277

280278
int pointsRemaining = nPosition;
281279
int ringNumber = 1;
@@ -307,8 +305,7 @@ void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRe
307305
}
308306
case Grid:
309307
{
310-
double centerDiagonal = symbolContext.renderContext().convertToPainterUnits( M_SQRT2 * mCenterSymbol->size(),
311-
mCenterSymbol->sizeUnit(), mCenterSymbol->sizeMapUnitScale() );
308+
double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2;
312309
int pointsRemaining = nPosition;
313310
gridSize = std::ceil( std::sqrt( pointsRemaining ) );
314311
if ( pointsRemaining - std::pow( gridSize - 1, 2 ) < gridSize )

src/core/symbology/qgssymbol.cpp

+30
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,21 @@ double QgsMarkerSymbol::size() const
13031303
return maxSize;
13041304
}
13051305

1306+
double QgsMarkerSymbol::size( const QgsRenderContext &context ) const
1307+
{
1308+
// return size of the largest symbol
1309+
double maxSize = 0;
1310+
for ( QgsSymbolLayer *layer : mLayers )
1311+
{
1312+
if ( layer->type() != QgsSymbol::Marker )
1313+
continue;
1314+
const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1315+
const double layerSize = context.convertToPainterUnits( markerLayer->size(), markerLayer->sizeUnit(), markerLayer->sizeMapUnitScale() );
1316+
maxSize = std::max( maxSize, layerSize );
1317+
}
1318+
return maxSize;
1319+
}
1320+
13061321
void QgsMarkerSymbol::setSizeUnit( QgsUnitTypes::RenderUnit unit )
13071322
{
13081323
Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
@@ -1625,6 +1640,21 @@ double QgsLineSymbol::width() const
16251640
return maxWidth;
16261641
}
16271642

1643+
double QgsLineSymbol::width( const QgsRenderContext &context ) const
1644+
{
1645+
// return width of the largest symbol
1646+
double maxWidth = 0;
1647+
for ( QgsSymbolLayer *layer : mLayers )
1648+
{
1649+
if ( layer->type() != QgsSymbol::Line )
1650+
continue;
1651+
const QgsLineSymbolLayer *lineLayer = static_cast<const QgsLineSymbolLayer *>( layer );
1652+
const double layerWidth = lineLayer->width( context );
1653+
maxWidth = std::max( maxWidth, layerWidth );
1654+
}
1655+
return maxWidth;
1656+
}
1657+
16281658
void QgsLineSymbol::setDataDefinedWidth( const QgsProperty &property )
16291659
{
16301660
const double symbolWidth = width();

0 commit comments

Comments
 (0)