mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-18 00:03:05 -04:00
Allow for exact calculation of symbol sizes with mixed layer units
Fixes #21143
This commit is contained in:
parent
427cb0b27a
commit
867e39947b
@ -223,6 +223,8 @@ Create a new MarkerLineSymbolLayerV2 from SLD
|
|||||||
|
|
||||||
virtual double width() const;
|
virtual double width() const;
|
||||||
|
|
||||||
|
virtual double width( const QgsRenderContext &context ) const;
|
||||||
|
|
||||||
|
|
||||||
virtual double estimateMaxBleed( const QgsRenderContext &context ) const;
|
virtual double estimateMaxBleed( const QgsRenderContext &context ) const;
|
||||||
|
|
||||||
|
@ -687,6 +687,10 @@ Will take ownership.
|
|||||||
|
|
||||||
class QgsMarkerSymbol : QgsSymbol
|
class QgsMarkerSymbol : QgsSymbol
|
||||||
{
|
{
|
||||||
|
%Docstring
|
||||||
|
|
||||||
|
A marker symbol type, for rendering Point and MultiPoint geometries.
|
||||||
|
%End
|
||||||
|
|
||||||
%TypeHeaderCode
|
%TypeHeaderCode
|
||||||
#include "qgssymbol.h"
|
#include "qgssymbol.h"
|
||||||
@ -700,6 +704,11 @@ This is a convenience method for easier creation of marker symbols.
|
|||||||
%End
|
%End
|
||||||
|
|
||||||
QgsMarkerSymbol( const QgsSymbolLayerList &layers /Transfer/ = QgsSymbolLayerList() );
|
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 );
|
void setAngle( double symbolAngle );
|
||||||
%Docstring
|
%Docstring
|
||||||
@ -770,14 +779,37 @@ will be scaled to maintain their current relative size to the whole symbol size.
|
|||||||
|
|
||||||
double size() const;
|
double size() const;
|
||||||
%Docstring
|
%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.
|
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:`setSize`
|
||||||
|
|
||||||
.. seealso:: :py:func:`sizeUnit`
|
.. seealso:: :py:func:`sizeUnit`
|
||||||
|
|
||||||
.. seealso:: :py:func:`sizeMapUnitScale`
|
.. 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
|
%End
|
||||||
|
|
||||||
void setSizeUnit( QgsUnitTypes::RenderUnit unit );
|
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
|
class QgsLineSymbol : QgsSymbol
|
||||||
{
|
{
|
||||||
|
%Docstring
|
||||||
|
|
||||||
|
A line symbol type, for rendering LineString and MultiLineString geometries.
|
||||||
|
%End
|
||||||
|
|
||||||
%TypeHeaderCode
|
%TypeHeaderCode
|
||||||
#include "qgssymbol.h"
|
#include "qgssymbol.h"
|
||||||
@ -903,9 +939,46 @@ This is a convenience method for easier creation of line symbols.
|
|||||||
%End
|
%End
|
||||||
|
|
||||||
QgsLineSymbol( const QgsSymbolLayerList &layers /Transfer/ = QgsSymbolLayerList() );
|
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 );
|
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;
|
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 );
|
void setDataDefinedWidth( const QgsProperty &property );
|
||||||
%Docstring
|
%Docstring
|
||||||
@ -938,6 +1011,10 @@ Returns data defined width for whole symbol (including all symbol layers).
|
|||||||
|
|
||||||
class QgsFillSymbol : QgsSymbol
|
class QgsFillSymbol : QgsSymbol
|
||||||
{
|
{
|
||||||
|
%Docstring
|
||||||
|
|
||||||
|
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
|
||||||
|
%End
|
||||||
|
|
||||||
%TypeHeaderCode
|
%TypeHeaderCode
|
||||||
#include "qgssymbol.h"
|
#include "qgssymbol.h"
|
||||||
@ -951,6 +1028,11 @@ This is a convenience method for easier creation of fill symbols.
|
|||||||
%End
|
%End
|
||||||
|
|
||||||
QgsFillSymbol( const QgsSymbolLayerList &layers /Transfer/ = QgsSymbolLayerList() );
|
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 setAngle( double angle );
|
||||||
void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, const QgsFeature *f, QgsRenderContext &context, int layer = -1, bool selected = false );
|
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 renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
|
||||||
|
|
||||||
virtual void setWidth( double width );
|
virtual void setWidth( double width );
|
||||||
|
|
||||||
virtual double width() const;
|
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;
|
double offset() const;
|
||||||
void setOffset( double offset );
|
void setOffset( double offset );
|
||||||
|
@ -421,7 +421,7 @@ QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemC
|
|||||||
if ( QgsMarkerSymbol *markerSymbol = dynamic_cast<QgsMarkerSymbol *>( s ) )
|
if ( QgsMarkerSymbol *markerSymbol = dynamic_cast<QgsMarkerSymbol *>( s ) )
|
||||||
{
|
{
|
||||||
// allow marker symbol to occupy bigger area if necessary
|
// 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;
|
height = size;
|
||||||
width = size;
|
width = size;
|
||||||
if ( width < settings.symbolSize().width() )
|
if ( width < settings.symbolSize().width() )
|
||||||
|
@ -1113,7 +1113,8 @@ void QgsMarkerLineSymbolLayer::renderPolylineVertex( const QPolygonF &points, Qg
|
|||||||
|| ( placement == CurvePoint && vId.type == QgsVertexId::CurveVertex ) )
|
|| ( placement == CurvePoint && vId.type == QgsVertexId::CurveVertex ) )
|
||||||
{
|
{
|
||||||
//transform
|
//transform
|
||||||
x = vPoint.x(), y = vPoint.y();
|
x = vPoint.x();
|
||||||
|
y = vPoint.y();
|
||||||
z = 0.0;
|
z = 0.0;
|
||||||
if ( ct.isValid() )
|
if ( ct.isValid() )
|
||||||
{
|
{
|
||||||
@ -1618,6 +1619,11 @@ double QgsMarkerLineSymbolLayer::width() const
|
|||||||
return mMarker->size();
|
return mMarker->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double QgsMarkerLineSymbolLayer::width( const QgsRenderContext &context ) const
|
||||||
|
{
|
||||||
|
return mMarker->size( context );
|
||||||
|
}
|
||||||
|
|
||||||
void QgsMarkerLineSymbolLayer::setOutputUnit( QgsUnitTypes::RenderUnit unit )
|
void QgsMarkerLineSymbolLayer::setOutputUnit( QgsUnitTypes::RenderUnit unit )
|
||||||
{
|
{
|
||||||
QgsLineSymbolLayer::setOutputUnit( unit );
|
QgsLineSymbolLayer::setOutputUnit( unit );
|
||||||
@ -1675,7 +1681,7 @@ bool QgsMarkerLineSymbolLayer::hasDataDefinedProperties() const
|
|||||||
|
|
||||||
double QgsMarkerLineSymbolLayer::estimateMaxBleed( const QgsRenderContext &context ) 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 );
|
context.convertToPainterUnits( std::fabs( mOffset ), mOffsetUnit, mOffsetMapUnitScale );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,6 +234,7 @@ class CORE_EXPORT QgsMarkerLineSymbolLayer : public QgsLineSymbolLayer
|
|||||||
|
|
||||||
void setWidth( double width ) override;
|
void setWidth( double width ) override;
|
||||||
double width() const override;
|
double width() const override;
|
||||||
|
double width( const QgsRenderContext &context ) const override;
|
||||||
|
|
||||||
double estimateMaxBleed( 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
|
//calculate max diagonal size from all symbols in group
|
||||||
double diagonal = 0;
|
double diagonal = 0;
|
||||||
|
|
||||||
Q_FOREACH ( const GroupedFeature &feature, group )
|
for ( const GroupedFeature &feature : group )
|
||||||
{
|
{
|
||||||
if ( QgsMarkerSymbol *symbol = feature.symbol() )
|
if ( QgsMarkerSymbol *symbol = feature.symbol() )
|
||||||
{
|
{
|
||||||
diagonal = std::max( diagonal, context.convertToPainterUnits( M_SQRT2 * symbol->size(),
|
diagonal = std::max( diagonal, M_SQRT2 * symbol->size( context ) );
|
||||||
symbol->sizeUnit(), symbol->sizeMapUnitScale() ) );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,8 +273,7 @@ void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRe
|
|||||||
}
|
}
|
||||||
case ConcentricRings:
|
case ConcentricRings:
|
||||||
{
|
{
|
||||||
double centerDiagonal = symbolContext.renderContext().convertToPainterUnits( M_SQRT2 * mCenterSymbol->size(),
|
double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2;
|
||||||
mCenterSymbol->sizeUnit(), mCenterSymbol->sizeMapUnitScale() );
|
|
||||||
|
|
||||||
int pointsRemaining = nPosition;
|
int pointsRemaining = nPosition;
|
||||||
int ringNumber = 1;
|
int ringNumber = 1;
|
||||||
@ -307,8 +305,7 @@ void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRe
|
|||||||
}
|
}
|
||||||
case Grid:
|
case Grid:
|
||||||
{
|
{
|
||||||
double centerDiagonal = symbolContext.renderContext().convertToPainterUnits( M_SQRT2 * mCenterSymbol->size(),
|
double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2;
|
||||||
mCenterSymbol->sizeUnit(), mCenterSymbol->sizeMapUnitScale() );
|
|
||||||
int pointsRemaining = nPosition;
|
int pointsRemaining = nPosition;
|
||||||
gridSize = std::ceil( std::sqrt( pointsRemaining ) );
|
gridSize = std::ceil( std::sqrt( pointsRemaining ) );
|
||||||
if ( pointsRemaining - std::pow( gridSize - 1, 2 ) < gridSize )
|
if ( pointsRemaining - std::pow( gridSize - 1, 2 ) < gridSize )
|
||||||
|
@ -1312,6 +1312,21 @@ double QgsMarkerSymbol::size() const
|
|||||||
return maxSize;
|
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 )
|
void QgsMarkerSymbol::setSizeUnit( QgsUnitTypes::RenderUnit unit )
|
||||||
{
|
{
|
||||||
Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
|
Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
|
||||||
@ -1634,6 +1649,21 @@ double QgsLineSymbol::width() const
|
|||||||
return maxWidth;
|
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 )
|
void QgsLineSymbol::setDataDefinedWidth( const QgsProperty &property )
|
||||||
{
|
{
|
||||||
const double symbolWidth = width();
|
const double symbolWidth = width();
|
||||||
|
@ -726,6 +726,8 @@ class CORE_EXPORT QgsSymbolRenderContext
|
|||||||
/**
|
/**
|
||||||
* \ingroup core
|
* \ingroup core
|
||||||
* \class QgsMarkerSymbol
|
* \class QgsMarkerSymbol
|
||||||
|
*
|
||||||
|
* A marker symbol type, for rendering Point and MultiPoint geometries.
|
||||||
*/
|
*/
|
||||||
class CORE_EXPORT QgsMarkerSymbol : public QgsSymbol
|
class CORE_EXPORT QgsMarkerSymbol : public QgsSymbol
|
||||||
{
|
{
|
||||||
@ -737,6 +739,11 @@ class CORE_EXPORT QgsMarkerSymbol : public QgsSymbol
|
|||||||
*/
|
*/
|
||||||
static QgsMarkerSymbol *createSimple( const QgsStringMap &properties ) SIP_FACTORY;
|
static QgsMarkerSymbol *createSimple( const QgsStringMap &properties ) SIP_FACTORY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for QgsMarkerSymbol, with the specified list of initial symbol \a layers.
|
||||||
|
*
|
||||||
|
* Ownership of the \a layers are transferred to the symbol.
|
||||||
|
*/
|
||||||
QgsMarkerSymbol( const QgsSymbolLayerList &layers SIP_TRANSFER = QgsSymbolLayerList() );
|
QgsMarkerSymbol( const QgsSymbolLayerList &layers SIP_TRANSFER = QgsSymbolLayerList() );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -792,14 +799,34 @@ class CORE_EXPORT QgsMarkerSymbol : public QgsSymbol
|
|||||||
void setSize( double size );
|
void setSize( double size );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
* 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 QgsRenderContext
|
||||||
|
* argument instead for accurate sizes in this case.
|
||||||
|
*
|
||||||
* \see setSize()
|
* \see setSize()
|
||||||
* \see sizeUnit()
|
* \see sizeUnit()
|
||||||
* \see sizeMapUnitScale()
|
* \see sizeMapUnitScale()
|
||||||
*/
|
*/
|
||||||
double size() const;
|
double size() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 \a context.
|
||||||
|
*
|
||||||
|
* \see setSize()
|
||||||
|
* \see sizeUnit()
|
||||||
|
* \see sizeMapUnitScale()
|
||||||
|
*
|
||||||
|
* \since QGIS 3.4.5
|
||||||
|
*/
|
||||||
|
double size( const QgsRenderContext &context ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the size units for the whole symbol (including all symbol layers).
|
* Sets the size units for the whole symbol (including all symbol layers).
|
||||||
* \param unit size units
|
* \param unit size units
|
||||||
@ -887,6 +914,8 @@ class CORE_EXPORT QgsMarkerSymbol : public QgsSymbol
|
|||||||
/**
|
/**
|
||||||
* \ingroup core
|
* \ingroup core
|
||||||
* \class QgsLineSymbol
|
* \class QgsLineSymbol
|
||||||
|
*
|
||||||
|
* A line symbol type, for rendering LineString and MultiLineString geometries.
|
||||||
*/
|
*/
|
||||||
class CORE_EXPORT QgsLineSymbol : public QgsSymbol
|
class CORE_EXPORT QgsLineSymbol : public QgsSymbol
|
||||||
{
|
{
|
||||||
@ -898,11 +927,46 @@ class CORE_EXPORT QgsLineSymbol : public QgsSymbol
|
|||||||
*/
|
*/
|
||||||
static QgsLineSymbol *createSimple( const QgsStringMap &properties ) SIP_FACTORY;
|
static QgsLineSymbol *createSimple( const QgsStringMap &properties ) SIP_FACTORY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for QgsLineSymbol, with the specified list of initial symbol \a layers.
|
||||||
|
*
|
||||||
|
* Ownership of the \a layers are transferred to the symbol.
|
||||||
|
*/
|
||||||
QgsLineSymbol( const QgsSymbolLayerList &layers SIP_TRANSFER = QgsSymbolLayerList() );
|
QgsLineSymbol( const QgsSymbolLayerList &layers SIP_TRANSFER = QgsSymbolLayerList() );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the \a width for the whole line symbol. Individual symbol layer sizes
|
||||||
|
* will be scaled to maintain their current relative size to the whole symbol size.
|
||||||
|
*
|
||||||
|
* \see width()
|
||||||
|
*/
|
||||||
void setWidth( double width );
|
void setWidth( double width );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 QgsRenderContext
|
||||||
|
* argument instead for accurate sizes in this case.
|
||||||
|
*
|
||||||
|
* \see setWidth()
|
||||||
|
*/
|
||||||
double width() const;
|
double width() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 \a context.
|
||||||
|
*
|
||||||
|
* \see setWidth()
|
||||||
|
*
|
||||||
|
* \since QGIS 3.4.5
|
||||||
|
*/
|
||||||
|
double width( const QgsRenderContext &context ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set data defined width for whole symbol (including all symbol layers).
|
* Set data defined width for whole symbol (including all symbol layers).
|
||||||
* \see dataDefinedWidth()
|
* \see dataDefinedWidth()
|
||||||
@ -933,6 +997,8 @@ class CORE_EXPORT QgsLineSymbol : public QgsSymbol
|
|||||||
/**
|
/**
|
||||||
* \ingroup core
|
* \ingroup core
|
||||||
* \class QgsFillSymbol
|
* \class QgsFillSymbol
|
||||||
|
*
|
||||||
|
* A fill symbol type, for rendering Polygon and MultiPolygon geometries.
|
||||||
*/
|
*/
|
||||||
class CORE_EXPORT QgsFillSymbol : public QgsSymbol
|
class CORE_EXPORT QgsFillSymbol : public QgsSymbol
|
||||||
{
|
{
|
||||||
@ -944,6 +1010,11 @@ class CORE_EXPORT QgsFillSymbol : public QgsSymbol
|
|||||||
*/
|
*/
|
||||||
static QgsFillSymbol *createSimple( const QgsStringMap &properties ) SIP_FACTORY;
|
static QgsFillSymbol *createSimple( const QgsStringMap &properties ) SIP_FACTORY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for QgsFillSymbol, with the specified list of initial symbol \a layers.
|
||||||
|
*
|
||||||
|
* Ownership of the \a layers are transferred to the symbol.
|
||||||
|
*/
|
||||||
QgsFillSymbol( const QgsSymbolLayerList &layers SIP_TRANSFER = QgsSymbolLayerList() );
|
QgsFillSymbol( const QgsSymbolLayerList &layers SIP_TRANSFER = QgsSymbolLayerList() );
|
||||||
void setAngle( double angle );
|
void setAngle( double angle );
|
||||||
void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, const QgsFeature *f, QgsRenderContext &context, int layer = -1, bool selected = false );
|
void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, const QgsFeature *f, QgsRenderContext &context, int layer = -1, bool selected = false );
|
||||||
|
@ -656,6 +656,11 @@ void QgsLineSymbolLayer::renderPolygonStroke( const QPolygonF &points, QList<QPo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double QgsLineSymbolLayer::width( const QgsRenderContext &context ) const
|
||||||
|
{
|
||||||
|
return context.convertToPainterUnits( mWidth, mWidthUnit, mWidthMapUnitScale );
|
||||||
|
}
|
||||||
|
|
||||||
double QgsLineSymbolLayer::dxfWidth( const QgsDxfExport &e, QgsSymbolRenderContext &context ) const
|
double QgsLineSymbolLayer::dxfWidth( const QgsDxfExport &e, QgsSymbolRenderContext &context ) const
|
||||||
{
|
{
|
||||||
Q_UNUSED( context );
|
Q_UNUSED( context );
|
||||||
|
@ -791,8 +791,30 @@ class CORE_EXPORT QgsLineSymbolLayer : public QgsSymbolLayer
|
|||||||
virtual void renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
|
virtual void renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
|
||||||
|
|
||||||
virtual void setWidth( double width ) { mWidth = width; }
|
virtual void setWidth( double width ) { mWidth = width; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 QgsRenderContext
|
||||||
|
* argument instead for accurate sizes in this case.
|
||||||
|
*
|
||||||
|
* \see setWidth()
|
||||||
|
*/
|
||||||
virtual double width() const { return mWidth; }
|
virtual double width() const { return mWidth; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 \a context.
|
||||||
|
*
|
||||||
|
* \see setWidth()
|
||||||
|
*
|
||||||
|
* \since QGIS 3.4.5
|
||||||
|
*/
|
||||||
|
virtual double width( const QgsRenderContext &context ) const;
|
||||||
|
|
||||||
double offset() const { return mOffset; }
|
double offset() const { return mOffset; }
|
||||||
void setOffset( double offset ) { mOffset = offset; }
|
void setOffset( double offset ) { mOffset = offset; }
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ import qgis # NOQA
|
|||||||
|
|
||||||
from utilities import unitTestDataPath
|
from utilities import unitTestDataPath
|
||||||
|
|
||||||
from qgis.PyQt.QtCore import QDir, Qt
|
from qgis.PyQt.QtCore import QDir, Qt, QSize
|
||||||
from qgis.PyQt.QtGui import QImage, QColor, QPainter
|
from qgis.PyQt.QtGui import QImage, QColor, QPainter
|
||||||
from qgis.PyQt.QtXml import QDomDocument
|
from qgis.PyQt.QtXml import QDomDocument
|
||||||
|
|
||||||
@ -49,7 +49,9 @@ from qgis.core import (QgsGeometry,
|
|||||||
QgsFontUtils,
|
QgsFontUtils,
|
||||||
QgsLineSymbol,
|
QgsLineSymbol,
|
||||||
QgsSymbolLayer,
|
QgsSymbolLayer,
|
||||||
QgsProperty
|
QgsProperty,
|
||||||
|
QgsRectangle,
|
||||||
|
QgsUnitTypes
|
||||||
)
|
)
|
||||||
|
|
||||||
from qgis.testing import unittest, start_app
|
from qgis.testing import unittest, start_app
|
||||||
@ -68,6 +70,38 @@ class TestQgsMarkerLineSymbolLayer(unittest.TestCase):
|
|||||||
with open(report_file_path, 'a') as report_file:
|
with open(report_file_path, 'a') as report_file:
|
||||||
report_file.write(self.report)
|
report_file.write(self.report)
|
||||||
|
|
||||||
|
def testWidth(self):
|
||||||
|
ms = QgsMapSettings()
|
||||||
|
extent = QgsRectangle(100, 200, 100, 200)
|
||||||
|
ms.setExtent(extent)
|
||||||
|
ms.setOutputSize(QSize(400, 400))
|
||||||
|
context = QgsRenderContext.fromMapSettings(ms)
|
||||||
|
context.setScaleFactor(96 / 25.4) # 96 DPI
|
||||||
|
ms.setExtent(QgsRectangle(100, 150, 100, 150))
|
||||||
|
ms.setOutputDpi(ms.outputDpi() * 2)
|
||||||
|
context2 = QgsRenderContext.fromMapSettings(ms)
|
||||||
|
context2.setScaleFactor(300 / 25.4)
|
||||||
|
|
||||||
|
s = QgsFillSymbol()
|
||||||
|
s.deleteSymbolLayer(0)
|
||||||
|
|
||||||
|
marker_line = QgsMarkerLineSymbolLayer(True)
|
||||||
|
marker_line.setPlacement(QgsMarkerLineSymbolLayer.FirstVertex)
|
||||||
|
marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Triangle, 10)
|
||||||
|
marker.setColor(QColor(255, 0, 0))
|
||||||
|
marker.setStrokeStyle(Qt.NoPen)
|
||||||
|
marker_symbol = QgsMarkerSymbol()
|
||||||
|
marker_symbol.changeSymbolLayer(0, marker)
|
||||||
|
marker_line.setSubSymbol(marker_symbol)
|
||||||
|
|
||||||
|
self.assertEqual(marker_line.width(), 10)
|
||||||
|
self.assertAlmostEqual(marker_line.width(context), 37.795275590551185, 3)
|
||||||
|
self.assertAlmostEqual(marker_line.width(context2), 118.11023622047244, 3)
|
||||||
|
|
||||||
|
marker_line.subSymbol().setSizeUnit(QgsUnitTypes.RenderPixels)
|
||||||
|
self.assertAlmostEqual(marker_line.width(context), 10.0, 3)
|
||||||
|
self.assertAlmostEqual(marker_line.width(context2), 10.0, 3)
|
||||||
|
|
||||||
def testRingFilter(self):
|
def testRingFilter(self):
|
||||||
# test filtering rings during rendering
|
# test filtering rings during rendering
|
||||||
s = QgsFillSymbol()
|
s = QgsFillSymbol()
|
||||||
|
@ -27,7 +27,7 @@ import qgis # NOQA
|
|||||||
|
|
||||||
from utilities import unitTestDataPath
|
from utilities import unitTestDataPath
|
||||||
|
|
||||||
from qgis.PyQt.QtCore import QDir, Qt
|
from qgis.PyQt.QtCore import QDir, Qt, QSize
|
||||||
from qgis.PyQt.QtGui import QImage, QColor, QPainter
|
from qgis.PyQt.QtGui import QImage, QColor, QPainter
|
||||||
from qgis.PyQt.QtXml import QDomDocument
|
from qgis.PyQt.QtXml import QDomDocument
|
||||||
|
|
||||||
@ -48,6 +48,7 @@ from qgis.core import (QgsGeometry,
|
|||||||
QgsRenderChecker,
|
QgsRenderChecker,
|
||||||
QgsSimpleMarkerSymbolLayer,
|
QgsSimpleMarkerSymbolLayer,
|
||||||
QgsSimpleMarkerSymbolLayerBase,
|
QgsSimpleMarkerSymbolLayerBase,
|
||||||
|
QgsSimpleLineSymbolLayer,
|
||||||
QgsSimpleFillSymbolLayer,
|
QgsSimpleFillSymbolLayer,
|
||||||
QgsUnitTypes,
|
QgsUnitTypes,
|
||||||
QgsWkbTypes,
|
QgsWkbTypes,
|
||||||
@ -509,6 +510,16 @@ class TestQgsMarkerSymbol(unittest.TestCase):
|
|||||||
|
|
||||||
def testSize(self):
|
def testSize(self):
|
||||||
# test size and setSize
|
# test size and setSize
|
||||||
|
ms = QgsMapSettings()
|
||||||
|
extent = QgsRectangle(100, 200, 100, 200)
|
||||||
|
ms.setExtent(extent)
|
||||||
|
ms.setOutputSize(QSize(400, 400))
|
||||||
|
context = QgsRenderContext.fromMapSettings(ms)
|
||||||
|
context.setScaleFactor(96 / 25.4) # 96 DPI
|
||||||
|
ms.setExtent(QgsRectangle(100, 150, 100, 150))
|
||||||
|
ms.setOutputDpi(ms.outputDpi() * 2)
|
||||||
|
context2 = QgsRenderContext.fromMapSettings(ms)
|
||||||
|
context2.setScaleFactor(300 / 25.4)
|
||||||
|
|
||||||
# create a marker symbol with a single layer
|
# create a marker symbol with a single layer
|
||||||
markerSymbol = QgsMarkerSymbol()
|
markerSymbol = QgsMarkerSymbol()
|
||||||
@ -517,9 +528,13 @@ class TestQgsMarkerSymbol(unittest.TestCase):
|
|||||||
QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Star, color=QColor(255, 0, 0),
|
QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Star, color=QColor(255, 0, 0),
|
||||||
strokeColor=QColor(0, 255, 0), size=10))
|
strokeColor=QColor(0, 255, 0), size=10))
|
||||||
self.assertEqual(markerSymbol.size(), 10)
|
self.assertEqual(markerSymbol.size(), 10)
|
||||||
|
self.assertAlmostEqual(markerSymbol.size(context), 37.795275590551185, 3)
|
||||||
|
self.assertAlmostEqual(markerSymbol.size(context2), 118.11023622047244, 3)
|
||||||
markerSymbol.setSize(20)
|
markerSymbol.setSize(20)
|
||||||
self.assertEqual(markerSymbol.size(), 20)
|
self.assertEqual(markerSymbol.size(), 20)
|
||||||
self.assertEqual(markerSymbol.symbolLayer(0).size(), 20)
|
self.assertEqual(markerSymbol.symbolLayer(0).size(), 20)
|
||||||
|
self.assertAlmostEqual(markerSymbol.size(context), 75.59055118, 3)
|
||||||
|
self.assertAlmostEqual(markerSymbol.size(context2), 236.2204724409449, 3)
|
||||||
|
|
||||||
# add additional layers
|
# add additional layers
|
||||||
markerSymbol.appendSymbolLayer(
|
markerSymbol.appendSymbolLayer(
|
||||||
@ -529,6 +544,9 @@ class TestQgsMarkerSymbol(unittest.TestCase):
|
|||||||
QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Star, color=QColor(255, 0, 0),
|
QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Star, color=QColor(255, 0, 0),
|
||||||
strokeColor=QColor(0, 255, 0), size=30))
|
strokeColor=QColor(0, 255, 0), size=30))
|
||||||
self.assertEqual(markerSymbol.size(), 30)
|
self.assertEqual(markerSymbol.size(), 30)
|
||||||
|
self.assertAlmostEqual(markerSymbol.size(context), 113.38582677165356, 3)
|
||||||
|
self.assertAlmostEqual(markerSymbol.size(context2), 354.33070866141736, 3)
|
||||||
|
|
||||||
markerSymbol.setSize(3)
|
markerSymbol.setSize(3)
|
||||||
self.assertEqual(markerSymbol.size(), 3)
|
self.assertEqual(markerSymbol.size(), 3)
|
||||||
# layer sizes should maintain relative size
|
# layer sizes should maintain relative size
|
||||||
@ -536,6 +554,17 @@ class TestQgsMarkerSymbol(unittest.TestCase):
|
|||||||
self.assertEqual(markerSymbol.symbolLayer(1).size(), 1)
|
self.assertEqual(markerSymbol.symbolLayer(1).size(), 1)
|
||||||
self.assertEqual(markerSymbol.symbolLayer(2).size(), 3)
|
self.assertEqual(markerSymbol.symbolLayer(2).size(), 3)
|
||||||
|
|
||||||
|
# symbol layer in different size
|
||||||
|
markerSymbol.symbolLayer(1).setSize(15)
|
||||||
|
self.assertAlmostEqual(markerSymbol.size(context), 56.69291338582678, 3)
|
||||||
|
self.assertAlmostEqual(markerSymbol.size(context2), 177.16535433070868, 3)
|
||||||
|
markerSymbol.symbolLayer(1).setSizeUnit(QgsUnitTypes.RenderPixels)
|
||||||
|
self.assertAlmostEqual(markerSymbol.size(context), 15, 3)
|
||||||
|
self.assertAlmostEqual(markerSymbol.size(context2), 35.43307086614173, 3)
|
||||||
|
markerSymbol.symbolLayer(1).setSize(45)
|
||||||
|
self.assertAlmostEqual(markerSymbol.size(context), 45, 3)
|
||||||
|
self.assertAlmostEqual(markerSymbol.size(context2), 45, 3)
|
||||||
|
|
||||||
def testAngle(self):
|
def testAngle(self):
|
||||||
# test angle and setAngle
|
# test angle and setAngle
|
||||||
|
|
||||||
@ -628,6 +657,71 @@ class TestQgsMarkerSymbol(unittest.TestCase):
|
|||||||
self.assertEqual(markerSymbol.symbolLayer(2).sizeMapUnitScale(), QgsMapUnitScale(3000, 4000))
|
self.assertEqual(markerSymbol.symbolLayer(2).sizeMapUnitScale(), QgsMapUnitScale(3000, 4000))
|
||||||
|
|
||||||
|
|
||||||
|
class TestQgsLineSymbol(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.report = "<h1>Python QgsLineSymbol Tests</h1>\n"
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
report_file_path = "%s/qgistest.html" % QDir.tempPath()
|
||||||
|
with open(report_file_path, 'a') as report_file:
|
||||||
|
report_file.write(self.report)
|
||||||
|
|
||||||
|
def testWidth(self):
|
||||||
|
# test width and setWidth
|
||||||
|
ms = QgsMapSettings()
|
||||||
|
extent = QgsRectangle(100, 200, 100, 200)
|
||||||
|
ms.setExtent(extent)
|
||||||
|
ms.setOutputSize(QSize(400, 400))
|
||||||
|
context = QgsRenderContext.fromMapSettings(ms)
|
||||||
|
context.setScaleFactor(96 / 25.4) # 96 DPI
|
||||||
|
ms.setExtent(QgsRectangle(100, 150, 100, 150))
|
||||||
|
ms.setOutputDpi(ms.outputDpi() * 2)
|
||||||
|
context2 = QgsRenderContext.fromMapSettings(ms)
|
||||||
|
context2.setScaleFactor(300 / 25.4)
|
||||||
|
|
||||||
|
# create a line symbol with a single layer
|
||||||
|
line_symbol = QgsLineSymbol()
|
||||||
|
line_symbol.deleteSymbolLayer(0)
|
||||||
|
line_symbol.appendSymbolLayer(
|
||||||
|
QgsSimpleLineSymbolLayer(color=QColor(255, 0, 0), width=10))
|
||||||
|
self.assertEqual(line_symbol.width(), 10)
|
||||||
|
self.assertAlmostEqual(line_symbol.width(context), 37.795275590551185, 3)
|
||||||
|
self.assertAlmostEqual(line_symbol.width(context2), 118.11023622047244, 3)
|
||||||
|
line_symbol.setWidth(20)
|
||||||
|
self.assertEqual(line_symbol.width(), 20)
|
||||||
|
self.assertEqual(line_symbol.symbolLayer(0).width(), 20)
|
||||||
|
self.assertAlmostEqual(line_symbol.width(context), 75.59055118, 3)
|
||||||
|
self.assertAlmostEqual(line_symbol.width(context2), 236.2204724409449, 3)
|
||||||
|
|
||||||
|
# add additional layers
|
||||||
|
line_symbol.appendSymbolLayer(
|
||||||
|
QgsSimpleLineSymbolLayer(color=QColor(255, 0, 0), width=10))
|
||||||
|
line_symbol.appendSymbolLayer(
|
||||||
|
QgsSimpleLineSymbolLayer(color=QColor(255, 0, 0), width=30))
|
||||||
|
self.assertEqual(line_symbol.width(), 30)
|
||||||
|
self.assertAlmostEqual(line_symbol.width(context), 113.38582677165356, 3)
|
||||||
|
self.assertAlmostEqual(line_symbol.width(context2), 354.33070866141736, 3)
|
||||||
|
|
||||||
|
line_symbol.setWidth(3)
|
||||||
|
self.assertEqual(line_symbol.width(), 3)
|
||||||
|
# layer widths should maintain relative size
|
||||||
|
self.assertEqual(line_symbol.symbolLayer(0).width(), 2)
|
||||||
|
self.assertEqual(line_symbol.symbolLayer(1).width(), 1)
|
||||||
|
self.assertEqual(line_symbol.symbolLayer(2).width(), 3)
|
||||||
|
|
||||||
|
# symbol layer in different size
|
||||||
|
line_symbol.symbolLayer(1).setWidth(15)
|
||||||
|
self.assertAlmostEqual(line_symbol.width(context), 56.69291338582678, 3)
|
||||||
|
self.assertAlmostEqual(line_symbol.width(context2), 177.16535433070868, 3)
|
||||||
|
line_symbol.symbolLayer(1).setWidthUnit(QgsUnitTypes.RenderPixels)
|
||||||
|
self.assertAlmostEqual(line_symbol.width(context), 15, 3)
|
||||||
|
self.assertAlmostEqual(line_symbol.width(context2), 35.43307086614173, 3)
|
||||||
|
line_symbol.symbolLayer(1).setWidth(45)
|
||||||
|
self.assertAlmostEqual(line_symbol.width(context), 45, 3)
|
||||||
|
self.assertAlmostEqual(line_symbol.width(context2), 45, 3)
|
||||||
|
|
||||||
|
|
||||||
class TestQgsFillSymbol(unittest.TestCase):
|
class TestQgsFillSymbol(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user