Skip to content
Permalink
Browse files

Merge pull request #37474 from mhugent/layout_legend_maximum_marker_size

Layout legend maximum marker size
  • Loading branch information
mhugent committed Jul 3, 2020
2 parents cdc2f7f + 1fda61e commit a60ddc0b1faf0cac70f9df629a9480905302fa71
@@ -201,6 +201,8 @@ Base class for graphical items within a :py:class:`QgsLayout`.
UndoLegendColumnCount,
UndoLegendSymbolWidth,
UndoLegendSymbolHeight,
UndoLegendMaxSymbolSize,
UndoLegendMinSymbolSize,
UndoLegendWmsLegendWidth,
UndoLegendWmsLegendHeight,
UndoLegendTitleSpaceBottom,
@@ -304,6 +304,34 @@ Sets the legend symbol ``width``.
.. seealso:: :py:func:`symbolWidth`
%End

double maxSymbolSize() const;
%Docstring
Returns the legend maximum symbol size (in mm). 0.0 means there is no maximum set

.. versionadded:: 3.16
%End

void setMaxSymbolSize( double size );
%Docstring
set maximum symbol size

:param size: maximum size (in mm) or 0.0 if no maximum

.. versionadded:: 3.16
%End

double minSymbolSize() const;
%Docstring
Returns the legend minimum symbol size (in mm). 0.0 means there is no minimum set
%End

void setMinSymbolSize( double size );
%Docstring
set minimum symbol size for symbol
@param size inimum size (in mm) or 0.0 if no minimum
%End


void setSymbolAlignment( Qt::AlignmentFlag alignment );
%Docstring
Sets the ``alignment`` for placement of legend symbols.
@@ -221,6 +221,28 @@ Returns the default symbol size (in millimeters) used for legend items.
Sets the default symbol size (in millimeters) used for legend items.

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

double maxSymbolSize() const;
%Docstring
Returns the maximum symbol size in mm
%End

void setMaxSymbolSize( double size );
%Docstring
Sets the maximum marker size in mm
@param size maximum size in mm
%End

double minSymbolSize() const;
%Docstring
Returns the minimum symbol size in mm
%End

void setMinSymbolSize( double size );
%Docstring
Sets the minimum symbol size in mm
@param size minimum size in mm
%End

void setSymbolAlignment( Qt::AlignmentFlag alignment );
@@ -1112,6 +1112,16 @@ will be scaled to maintain their current relative size to the whole symbol size.
.. seealso:: :py:func:`width`
%End

void setWidthUnit( QgsUnitTypes::RenderUnit unit );
%Docstring
Sets the width units for the whole symbol (including all symbol layers).

:param unit: size units

.. versionadded:: 3.16
%End


double width() const;
%Docstring
Returns the estimated width for the whole symbol, which is the maximum width of
@@ -813,6 +813,20 @@ Encodes a reference to a parametric SVG into a path with parameters according to
Converts a set of symbol layer id to a set of pointers to actual symbol layers carried by the feature renderer.

.. versionadded:: 3.12
%End

static QgsSymbol *restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height );
%Docstring
Creates a new symbol with size restricted to min/max size if original size is out of min/max range

:param s: the original symbol
:param minSize: the minimum size in mm
:param maxSize: the maximum size in mm
:param context: the render context
:param width: expected width, can be changed by the function
:param height: expected height, can be changed by this function

:return: 0 if size is within minSize/maxSize range. New symbol if size was out of min/max range. Caller takes ownership
%End
};

@@ -557,12 +557,24 @@ QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemC
double widthOffset = 0;
double heightOffset = 0;

double maxSymbolSize = settings.maxSymbolSize();
double minSymbolSize = settings.minSymbolSize();

if ( QgsMarkerSymbol *markerSymbol = dynamic_cast<QgsMarkerSymbol *>( s ) )
{
// allow marker symbol to occupy bigger area if necessary
double size = markerSymbol->size( *context ) / context->scaleFactor();
height = size;
width = size;
}

std::unique_ptr<QgsSymbol> minMaxSizeSymbol( QgsSymbolLayerUtils::restrictedSizeSymbol( s, minSymbolSize, maxSymbolSize, context, width, height ) );
if ( minMaxSizeSymbol )
{
s = minMaxSizeSymbol.get();
}

if ( s->type() == QgsSymbol::Marker )
{
if ( width < desiredWidth )
{
widthOffset = ( desiredWidth - width ) / 2.0;
@@ -572,7 +584,6 @@ QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemC
heightOffset = ( desiredHeight - height ) / 2.0;
}
}

if ( ctx && ctx->painter )
{
double currentYCoord = ctx->top + ( itemHeight - desiredHeight ) / 2;
@@ -252,6 +252,8 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
UndoLegendColumnCount, //!< Legend column count
UndoLegendSymbolWidth, //!< Legend symbol width
UndoLegendSymbolHeight, //!< Legend symbol height
UndoLegendMaxSymbolSize, //!< Legend maximum symbol size
UndoLegendMinSymbolSize, //!< Legend minimum symbol size
UndoLegendWmsLegendWidth, //!< Legend WMS width
UndoLegendWmsLegendHeight, //!< Legend WMS height
UndoLegendTitleSpaceBottom, //!< Legend title space
@@ -394,6 +394,26 @@ void QgsLayoutItemLegend::setSymbolWidth( double w )
mSettings.setSymbolSize( QSizeF( w, mSettings.symbolSize().height() ) );
}

double QgsLayoutItemLegend::maxSymbolSize() const
{
return mSettings.maxSymbolSize();
}

void QgsLayoutItemLegend::setMaxSymbolSize( double size )
{
mSettings.setMaxSymbolSize( size );
}

double QgsLayoutItemLegend::minSymbolSize() const
{
return mSettings.minSymbolSize();
}

void QgsLayoutItemLegend::setMinSymbolSize( double size )
{
mSettings.setMinSymbolSize( size );
}

void QgsLayoutItemLegend::setSymbolAlignment( Qt::AlignmentFlag alignment )
{
mSettings.setSymbolAlignment( alignment );
@@ -526,6 +546,8 @@ bool QgsLayoutItemLegend::writePropertiesToElement( QDomElement &legendElem, QDo

legendElem.setAttribute( QStringLiteral( "symbolWidth" ), QString::number( mSettings.symbolSize().width() ) );
legendElem.setAttribute( QStringLiteral( "symbolHeight" ), QString::number( mSettings.symbolSize().height() ) );
legendElem.setAttribute( QStringLiteral( "maxSymbolSize" ), QString::number( mSettings.maxSymbolSize() ) );
legendElem.setAttribute( QStringLiteral( "minSymbolSize" ), QString::number( mSettings.minSymbolSize() ) );

legendElem.setAttribute( QStringLiteral( "symbolAlignment" ), mSettings.symbolAlignment() );

@@ -621,6 +643,9 @@ bool QgsLayoutItemLegend::readPropertiesFromElement( const QDomElement &itemElem
mSettings.setSymbolSize( QSizeF( itemElem.attribute( QStringLiteral( "symbolWidth" ), QStringLiteral( "7.0" ) ).toDouble(), itemElem.attribute( QStringLiteral( "symbolHeight" ), QStringLiteral( "14.0" ) ).toDouble() ) );
mSettings.setSymbolAlignment( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "symbolAlignment" ), QString::number( Qt::AlignLeft ) ).toInt() ) );

mSettings.setMaxSymbolSize( itemElem.attribute( QStringLiteral( "maxSymbolSize" ), QStringLiteral( "0.0" ) ).toDouble() );
mSettings.setMinSymbolSize( itemElem.attribute( QStringLiteral( "minSymbolSize" ), QStringLiteral( "0.0" ) ).toDouble() );

mSettings.setWmsLegendSize( QSizeF( itemElem.attribute( QStringLiteral( "wmsLegendWidth" ), QStringLiteral( "50" ) ).toDouble(), itemElem.attribute( QStringLiteral( "wmsLegendHeight" ), QStringLiteral( "25" ) ).toDouble() ) );
mSettings.setLineSpacing( itemElem.attribute( QStringLiteral( "lineSpacing" ), QStringLiteral( "1.0" ) ).toDouble() );

@@ -318,6 +318,31 @@ class CORE_EXPORT QgsLayoutItemLegend : public QgsLayoutItem
*/
void setSymbolWidth( double width );

/**
* Returns the legend maximum symbol size (in mm). 0.0 means there is no maximum set
* \since QGIS 3.16
*/
double maxSymbolSize() const;

/**
* \brief set maximum symbol size
* \param size maximum size (in mm) or 0.0 if no maximum
* \since QGIS 3.16
*/
void setMaxSymbolSize( double size );

/**
* Returns the legend minimum symbol size (in mm). 0.0 means there is no minimum set
*/
double minSymbolSize() const;

/**
* @brief set minimum symbol size for symbol
* @param size inimum size (in mm) or 0.0 if no minimum
*/
void setMinSymbolSize( double size );


/**
* Sets the \a alignment for placement of legend symbols.
*
@@ -234,6 +234,28 @@ class CORE_EXPORT QgsLegendSettings
*/
void setSymbolSize( QSizeF s ) {mSymbolSize = s;}

/**
* Returns the maximum symbol size in mm
*/
double maxSymbolSize() const {return mMaxSymbolSize; }

/**
* Sets the maximum marker size in mm
* @param size maximum size in mm
*/
void setMaxSymbolSize( double size ) { mMaxSymbolSize = size;}

/**
* Returns the minimum symbol size in mm
*/
double minSymbolSize() const {return mMinSymbolSize; }

/**
* Sets the minimum symbol size in mm
* @param size minimum size in mm
*/
void setMinSymbolSize( double size ) { mMinSymbolSize = size;}

/**
* Sets the \a alignment for placement of legend symbols.
*
@@ -479,6 +501,12 @@ class CORE_EXPORT QgsLegendSettings
//! Width and height of symbol icon
QSizeF mSymbolSize;

//! Maximum marker symbol size (in mm)
double mMaxSymbolSize = 0.0;

//! Minimum marker symbol size (in mm)
double mMinSymbolSize = 0.0;

//! Width and height of WMS legendGraphic pixmap
QSizeF mWmsLegendSize;

@@ -1951,6 +1951,19 @@ void QgsLineSymbol::setWidth( double w )
}
}

void QgsLineSymbol::setWidthUnit( QgsUnitTypes::RenderUnit unit )
{
const auto constLLayers = mLayers;
for ( QgsSymbolLayer *layer : constLLayers )
{
if ( layer->type() != QgsSymbol::Line )
continue;

QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( layer );
lineLayer->setWidthUnit( unit );
}
}

double QgsLineSymbol::width() const
{
double maxWidth = 0;
@@ -1139,6 +1139,14 @@ class CORE_EXPORT QgsLineSymbol : public QgsSymbol
*/
void setWidth( double width );

/**
* Sets the width units for the whole symbol (including all symbol layers).
* \param unit size units
* \since QGIS 3.16
*/
void setWidthUnit( QgsUnitTypes::RenderUnit unit );


/**
* Returns the estimated width for the whole symbol, which is the maximum width of
* all marker symbol layers in the symbol.
@@ -4473,3 +4473,61 @@ QSet<const QgsSymbolLayer *> QgsSymbolLayerUtils::toSymbolLayerPointers( QgsFeat
renderer->accept( &visitor );
return visitor.mSymbolLayers;
}

QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height )
{
if ( !s || !context )
{
return 0;
}

double size;
const QgsMarkerSymbol *markerSymbol = dynamic_cast<const QgsMarkerSymbol *>( s );
const QgsLineSymbol *lineSymbol = dynamic_cast<const QgsLineSymbol *>( s );
if ( markerSymbol )
{
size = markerSymbol->size( *context );
}
else if ( lineSymbol )
{
size = lineSymbol->width( *context );
}
else
{
return 0; //not size restriction implemented for other symbol types
}

size /= context->scaleFactor();

if ( minSize > 0 && size < minSize )
{
size = minSize;
}
else if ( maxSize > 0 && size > maxSize )
{
size = maxSize;
}
else
{
return 0;
}

if ( markerSymbol )
{
QgsMarkerSymbol *ms = dynamic_cast<QgsMarkerSymbol *>( s->clone() );
ms->setSize( size );
ms->setSizeUnit( QgsUnitTypes::RenderMillimeters );
width = size;
height = size;
return ms;
}
else if ( lineSymbol )
{
QgsLineSymbol *ls = dynamic_cast<QgsLineSymbol *>( s->clone() );
ls->setWidth( size );
ls->setWidthUnit( QgsUnitTypes::RenderMillimeters );
height = size;
return ls;
}
return 0;
}
@@ -728,6 +728,18 @@ class CORE_EXPORT QgsSymbolLayerUtils
* \since QGIS 3.12
*/
static QSet<const QgsSymbolLayer *> toSymbolLayerPointers( QgsFeatureRenderer *renderer, const QSet<QgsSymbolLayerId> &symbolLayerIds );

/**
* \brief Creates a new symbol with size restricted to min/max size if original size is out of min/max range
* \param s the original symbol
* \param minSize the minimum size in mm
* \param maxSize the maximum size in mm
* \param context the render context
* \param width expected width, can be changed by the function
* \param height expected height, can be changed by this function
* \return 0 if size is within minSize/maxSize range. New symbol if size was out of min/max range. Caller takes ownership
*/
static QgsSymbol *restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height );
};

class QPolygonF;

0 comments on commit a60ddc0

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