Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[feature][layouts] Add subdivisions in ticks scalebar right segments
Adds the ability to create subdivisions for segments included in the right part of the ticksscalebar

Fixes #20341
  • Loading branch information
agiudiceandrea committed May 5, 2020
1 parent fdce7e2 commit a3397a8
Show file tree
Hide file tree
Showing 18 changed files with 311 additions and 16 deletions.
3 changes: 2 additions & 1 deletion python/core/auto_additions/qgsscalebarrenderer.py
Expand Up @@ -11,5 +11,6 @@
QgsScaleBarRenderer.Flag.FlagUsesLabelVerticalPlacement.__doc__ = "Renderer uses the QgsScaleBarSettings::labelVerticalPlacement() setting"
QgsScaleBarRenderer.Flag.FlagUsesLabelHorizontalPlacement.__doc__ = "Renderer uses the QgsScaleBarSettings::labelHorizontalPlacement() setting"
QgsScaleBarRenderer.Flag.FlagUsesAlignment.__doc__ = "Renderer uses the QgsScaleBarSettings::alignment() setting"
QgsScaleBarRenderer.Flag.__doc__ = 'Flags which control scalebar renderer behavior.\n\n.. versionadded:: 3.14\n\n' + '* ``FlagUsesLineSymbol``: ' + QgsScaleBarRenderer.Flag.FlagUsesLineSymbol.__doc__ + '\n' + '* ``FlagUsesFillSymbol``: ' + QgsScaleBarRenderer.Flag.FlagUsesFillSymbol.__doc__ + '\n' + '* ``FlagUsesAlternateFillSymbol``: ' + QgsScaleBarRenderer.Flag.FlagUsesAlternateFillSymbol.__doc__ + '\n' + '* ``FlagRespectsUnits``: ' + QgsScaleBarRenderer.Flag.FlagRespectsUnits.__doc__ + '\n' + '* ``FlagRespectsMapUnitsPerScaleBarUnit``: ' + QgsScaleBarRenderer.Flag.FlagRespectsMapUnitsPerScaleBarUnit.__doc__ + '\n' + '* ``FlagUsesUnitLabel``: ' + QgsScaleBarRenderer.Flag.FlagUsesUnitLabel.__doc__ + '\n' + '* ``FlagUsesSegments``: ' + QgsScaleBarRenderer.Flag.FlagUsesSegments.__doc__ + '\n' + '* ``FlagUsesLabelBarSpace``: ' + QgsScaleBarRenderer.Flag.FlagUsesLabelBarSpace.__doc__ + '\n' + '* ``FlagUsesLabelVerticalPlacement``: ' + QgsScaleBarRenderer.Flag.FlagUsesLabelVerticalPlacement.__doc__ + '\n' + '* ``FlagUsesLabelHorizontalPlacement``: ' + QgsScaleBarRenderer.Flag.FlagUsesLabelHorizontalPlacement.__doc__ + '\n' + '* ``FlagUsesAlignment``: ' + QgsScaleBarRenderer.Flag.FlagUsesAlignment.__doc__
QgsScaleBarRenderer.Flag.FlagUsesSubdivisions.__doc__ = "Renderer uses the scalebar subdivisions"
QgsScaleBarRenderer.Flag.__doc__ = 'Flags which control scalebar renderer behavior.\n\n.. versionadded:: 3.14\n\n' + '* ``FlagUsesLineSymbol``: ' + QgsScaleBarRenderer.Flag.FlagUsesLineSymbol.__doc__ + '\n' + '* ``FlagUsesFillSymbol``: ' + QgsScaleBarRenderer.Flag.FlagUsesFillSymbol.__doc__ + '\n' + '* ``FlagUsesAlternateFillSymbol``: ' + QgsScaleBarRenderer.Flag.FlagUsesAlternateFillSymbol.__doc__ + '\n' + '* ``FlagRespectsUnits``: ' + QgsScaleBarRenderer.Flag.FlagRespectsUnits.__doc__ + '\n' + '* ``FlagRespectsMapUnitsPerScaleBarUnit``: ' + QgsScaleBarRenderer.Flag.FlagRespectsMapUnitsPerScaleBarUnit.__doc__ + '\n' + '* ``FlagUsesUnitLabel``: ' + QgsScaleBarRenderer.Flag.FlagUsesUnitLabel.__doc__ + '\n' + '* ``FlagUsesSegments``: ' + QgsScaleBarRenderer.Flag.FlagUsesSegments.__doc__ + '\n' + '* ``FlagUsesLabelBarSpace``: ' + QgsScaleBarRenderer.Flag.FlagUsesLabelBarSpace.__doc__ + '\n' + '* ``FlagUsesLabelVerticalPlacement``: ' + QgsScaleBarRenderer.Flag.FlagUsesLabelVerticalPlacement.__doc__ + '\n' + '* ``FlagUsesLabelHorizontalPlacement``: ' + QgsScaleBarRenderer.Flag.FlagUsesLabelHorizontalPlacement.__doc__ + '\n' + '* ``FlagUsesAlignment``: ' + QgsScaleBarRenderer.Flag.FlagUsesAlignment.__doc__ + '\n' + '* ``FlagUsesSubdivisions``: ' + QgsScaleBarRenderer.Flag.FlagUsesSubdivisions.__doc__
# --
2 changes: 2 additions & 0 deletions python/core/auto_generated/layout/qgslayoutitem.sip.in
Expand Up @@ -223,6 +223,8 @@ Base class for graphical items within a :py:class:`QgsLayout`.
UndoScaleBarSegmentsLeft,
UndoScaleBarSegments,
UndoScaleBarHeight,
UndoScaleBarSubdivisions,
UndoScaleBarSubdivisionsHeight,
UndoScaleBarFontColor,
UndoScaleBarFillColor,
UndoScaleBarFillColor2,
Expand Down
36 changes: 36 additions & 0 deletions python/core/auto_generated/layout/qgslayoutitemscalebar.sip.in
Expand Up @@ -74,6 +74,42 @@ Sets the number of ``segments`` included in the left part of the scalebar.
.. seealso:: :py:func:`numberOfSegmentsLeft`

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

int numberOfSubdivisions() const;
%Docstring
Returns the number of subdivisions for segments included in the right part of the scalebar (only used for some scalebar types).

.. seealso:: :py:func:`setNumberOfSubdivisions`

.. versionadded:: 3.14
%End

void setNumberOfSubdivisions( int subdivisions );
%Docstring
Sets the number of ``subdivisions`` for segments included in the right part of the scalebar (only used for some scalebar types).

.. seealso:: :py:func:`numberOfSubdivisions`

.. versionadded:: 3.14
%End

double subdivisionsHeight() const;
%Docstring
Returns the scalebar subdivisions height (in millimeters) for segments included in the right part of the scalebar (only used for some scalebar types).

.. seealso:: :py:func:`setSubdivisionsHeight`

.. versionadded:: 3.14
%End

void setSubdivisionsHeight( double height );
%Docstring
Sets the scalebar subdivisions ``height`` (in millimeters) for segments included in the right part of the scalebar (only used for some scalebar types).

.. seealso:: :py:func:`subdivisionsHeight`

.. versionadded:: 3.14
%End

double unitsPerSegment() const;
Expand Down
Expand Up @@ -49,6 +49,7 @@ custom labeling.
FlagUsesLabelVerticalPlacement,
FlagUsesLabelHorizontalPlacement,
FlagUsesAlignment,
FlagUsesSubdivisions,
};
typedef QFlags<QgsScaleBarRenderer::Flag> Flags;

Expand Down
36 changes: 36 additions & 0 deletions python/core/auto_generated/scalebar/qgsscalebarsettings.sip.in
Expand Up @@ -95,6 +95,42 @@ Sets the number of ``segments`` included in the left part of the scalebar.
.. seealso:: :py:func:`numberOfSegmentsLeft`

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

int numberOfSubdivisions() const;
%Docstring
Returns the number of subdivisions for segments included in the right part of the scalebar (only used for some scalebar types).

.. seealso:: :py:func:`setNumberOfSubdivisions`

.. versionadded:: 3.14
%End

void setNumberOfSubdivisions( int subdivisions );
%Docstring
Sets the number of ``subdivisions`` for segments included in the right part of the scalebar (only used for some scalebar types).

.. seealso:: :py:func:`numberOfSubdivisions`

.. versionadded:: 3.14
%End

double subdivisionsHeight() const;
%Docstring
Returns the scalebar subdivisions height (in millimeters) for segments included in the right part of the scalebar (only used for some scalebar types).

.. seealso:: :py:func:`setSubdivisionsHeight`

.. versionadded:: 3.14
%End

void setSubdivisionsHeight( double height );
%Docstring
Sets the scalebar subdivisions ``height`` (in millimeters) for segments included in the right part of the scalebar (only used for some scalebar types).

.. seealso:: :py:func:`subdivisionsHeight`

.. versionadded:: 3.14
%End

double unitsPerSegment() const;
Expand Down
2 changes: 2 additions & 0 deletions src/core/layout/qgslayoutitem.h
Expand Up @@ -274,6 +274,8 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
UndoScaleBarSegmentsLeft, //!< Scalebar segments left
UndoScaleBarSegments, //!< Scalebar number of segments
UndoScaleBarHeight, //!< Scalebar height
UndoScaleBarSubdivisions, //!< Scalebar number of subdivisions
UndoScaleBarSubdivisionsHeight, //!< Scalebar subdivisions height
UndoScaleBarFontColor, //!< Scalebar font color
UndoScaleBarFillColor, //!< Scalebar fill color
UndoScaleBarFillColor2, //!< Scalebar secondary fill color
Expand Down
4 changes: 4 additions & 0 deletions src/core/layout/qgslayoutitemscalebar.cpp
Expand Up @@ -730,6 +730,8 @@ bool QgsLayoutItemScaleBar::writePropertiesToElement( QDomElement &composerScale
composerScaleBarElem.setAttribute( QStringLiteral( "boxContentSpace" ), QString::number( mSettings.boxContentSpace() ) );
composerScaleBarElem.setAttribute( QStringLiteral( "numSegments" ), mSettings.numberOfSegments() );
composerScaleBarElem.setAttribute( QStringLiteral( "numSegmentsLeft" ), mSettings.numberOfSegmentsLeft() );
composerScaleBarElem.setAttribute( QStringLiteral( "numSubdivisions" ), mSettings.numberOfSubdivisions() );
composerScaleBarElem.setAttribute( QStringLiteral( "subdivisionsHeight" ), mSettings.subdivisionsHeight() );
composerScaleBarElem.setAttribute( QStringLiteral( "numUnitsPerSegment" ), QString::number( mSettings.unitsPerSegment() ) );
composerScaleBarElem.setAttribute( QStringLiteral( "segmentSizeMode" ), mSettings.segmentSizeMode() );
composerScaleBarElem.setAttribute( QStringLiteral( "minBarWidth" ), mSettings.minimumBarWidth() );
Expand Down Expand Up @@ -837,6 +839,8 @@ bool QgsLayoutItemScaleBar::readPropertiesFromElement( const QDomElement &itemEl
mSettings.setBoxContentSpace( itemElem.attribute( QStringLiteral( "boxContentSpace" ), QStringLiteral( "1.0" ) ).toDouble() );
mSettings.setNumberOfSegments( itemElem.attribute( QStringLiteral( "numSegments" ), QStringLiteral( "2" ) ).toInt() );
mSettings.setNumberOfSegmentsLeft( itemElem.attribute( QStringLiteral( "numSegmentsLeft" ), QStringLiteral( "0" ) ).toInt() );
mSettings.setNumberOfSubdivisions( itemElem.attribute( QStringLiteral( "numSubdivisions" ), QStringLiteral( "0" ) ).toInt() );
mSettings.setSubdivisionsHeight( itemElem.attribute( QStringLiteral( "subdivisionsHeight" ), QStringLiteral( "1.5" ) ).toDouble() );
mSettings.setUnitsPerSegment( itemElem.attribute( QStringLiteral( "numUnitsPerSegment" ), QStringLiteral( "1.0" ) ).toDouble() );
mSettings.setSegmentSizeMode( static_cast<QgsScaleBarSettings::SegmentSizeMode>( itemElem.attribute( QStringLiteral( "segmentSizeMode" ), QStringLiteral( "0" ) ).toInt() ) );
mSettings.setMinimumBarWidth( itemElem.attribute( QStringLiteral( "minBarWidth" ), QStringLiteral( "50" ) ).toDouble() );
Expand Down
28 changes: 28 additions & 0 deletions src/core/layout/qgslayoutitemscalebar.h
Expand Up @@ -82,6 +82,34 @@ class CORE_EXPORT QgsLayoutItemScaleBar: public QgsLayoutItem
*/
void setNumberOfSegmentsLeft( int segments );

/**
* Returns the number of subdivisions for segments included in the right part of the scalebar (only used for some scalebar types).
* \see setNumberOfSubdivisions()
* \since QGIS 3.14
*/
int numberOfSubdivisions() const { return mSettings.numberOfSubdivisions(); }

/**
* Sets the number of \a subdivisions for segments included in the right part of the scalebar (only used for some scalebar types).
* \see numberOfSubdivisions()
* \since QGIS 3.14
*/
void setNumberOfSubdivisions( int subdivisions ) { mSettings.setNumberOfSubdivisions( subdivisions ); }

/**
* Returns the scalebar subdivisions height (in millimeters) for segments included in the right part of the scalebar (only used for some scalebar types).
* \see setSubdivisionsHeight()
* \since QGIS 3.14
*/
double subdivisionsHeight() const { return mSettings.subdivisionsHeight(); }

/**
* Sets the scalebar subdivisions \a height (in millimeters) for segments included in the right part of the scalebar (only used for some scalebar types).
* \see subdivisionsHeight()
* \since QGIS 3.14
*/
void setSubdivisionsHeight( double height ) { mSettings.setSubdivisionsHeight( height ); }

/**
* Returns the number of scalebar units per segment.
* \see setUnitsPerSegment()
Expand Down
1 change: 1 addition & 0 deletions src/core/scalebar/qgsscalebarrenderer.h
Expand Up @@ -81,6 +81,7 @@ class CORE_EXPORT QgsScaleBarRenderer
FlagUsesLabelVerticalPlacement = 1 << 8, //!< Renderer uses the QgsScaleBarSettings::labelVerticalPlacement() setting
FlagUsesLabelHorizontalPlacement = 1 << 8, //!< Renderer uses the QgsScaleBarSettings::labelHorizontalPlacement() setting
FlagUsesAlignment = 1 << 9, //!< Renderer uses the QgsScaleBarSettings::alignment() setting
FlagUsesSubdivisions = 1 << 10, //!< Renderer uses the scalebar subdivisions
};
Q_DECLARE_FLAGS( Flags, Flag )

Expand Down
4 changes: 4 additions & 0 deletions src/core/scalebar/qgsscalebarsettings.cpp
Expand Up @@ -57,6 +57,8 @@ QgsScaleBarSettings::QgsScaleBarSettings()
QgsScaleBarSettings::QgsScaleBarSettings( const QgsScaleBarSettings &other )
: mNumSegments( other.mNumSegments )
, mNumSegmentsLeft( other.mNumSegmentsLeft )
, mNumSubdivisions( other.mNumSubdivisions )
, mSubdivisionsHeight( other.mSubdivisionsHeight )
, mNumUnitsPerSegment( other.mNumUnitsPerSegment )
, mNumMapUnitsPerScaleBarUnit( other.mNumMapUnitsPerScaleBarUnit )
, mSegmentSizeMode( other.mSegmentSizeMode )
Expand All @@ -83,6 +85,8 @@ QgsScaleBarSettings &QgsScaleBarSettings::operator=( const QgsScaleBarSettings &
{
mNumSegments = other.mNumSegments;
mNumSegmentsLeft = other.mNumSegmentsLeft;
mNumSubdivisions = other.mNumSubdivisions;
mSubdivisionsHeight = other.mSubdivisionsHeight;
mNumUnitsPerSegment = other.mNumUnitsPerSegment;
mNumMapUnitsPerScaleBarUnit = other.mNumMapUnitsPerScaleBarUnit;
mSegmentSizeMode = other.mSegmentSizeMode;
Expand Down
32 changes: 32 additions & 0 deletions src/core/scalebar/qgsscalebarsettings.h
Expand Up @@ -120,6 +120,34 @@ class CORE_EXPORT QgsScaleBarSettings
*/
void setNumberOfSegmentsLeft( int segments ) { mNumSegmentsLeft = segments; }

/**
* Returns the number of subdivisions for segments included in the right part of the scalebar (only used for some scalebar types).
* \see setNumberOfSubdivisions()
* \since QGIS 3.14
*/
int numberOfSubdivisions() const { return mNumSubdivisions; }

/**
* Sets the number of \a subdivisions for segments included in the right part of the scalebar (only used for some scalebar types).
* \see numberOfSubdivisions()
* \since QGIS 3.14
*/
void setNumberOfSubdivisions( int subdivisions ) { mNumSubdivisions = subdivisions; }

/**
* Returns the scalebar subdivisions height (in millimeters) for segments included in the right part of the scalebar (only used for some scalebar types).
* \see setSubdivisionsHeight()
* \since QGIS 3.14
*/
double subdivisionsHeight() const { return mSubdivisionsHeight; }

/**
* Sets the scalebar subdivisions \a height (in millimeters) for segments included in the right part of the scalebar (only used for some scalebar types).
* \see subdivisionsHeight()
* \since QGIS 3.14
*/
void setSubdivisionsHeight( double height ) { mSubdivisionsHeight = height; }

/**
* Returns the number of scalebar units per segment.
* \see setUnitsPerSegment()
Expand Down Expand Up @@ -585,6 +613,10 @@ class CORE_EXPORT QgsScaleBarSettings
int mNumSegments = 2;
//! Number of segments on left side
int mNumSegmentsLeft = 0;
//! Number of subdivisions on right side
int mNumSubdivisions = 0;
//! Height of subdivisions on right side
double mSubdivisionsHeight = 1.5;
//! Size of a segment (in map units)
double mNumUnitsPerSegment = 0;
//! Number of map units per scale bar units (e.g. 1000 to have km for a map with m units)
Expand Down
51 changes: 36 additions & 15 deletions src/core/scalebar/qgsticksscalebarrenderer.cpp
Expand Up @@ -78,7 +78,8 @@ QgsScaleBarRenderer::Flags QgsTicksScaleBarRenderer::flags() const
Flag::FlagUsesSegments |
Flag::FlagUsesLabelBarSpace |
Flag::FlagUsesLabelVerticalPlacement |
Flag::FlagUsesLabelHorizontalPlacement;
Flag::FlagUsesLabelHorizontalPlacement |
Flag::FlagUsesSubdivisions;
}

QgsTicksScaleBarRenderer *QgsTicksScaleBarRenderer::clone() const
Expand All @@ -99,6 +100,7 @@ void QgsTicksScaleBarRenderer::draw( QgsRenderContext &context, const QgsScaleBa
const double barTopPosition = scaledBoxContentSpace + ( settings.labelVerticalPlacement() == QgsScaleBarSettings::LabelAboveSegment ? fontMetrics.ascent() + scaledLabelBarSpace : 0 );
const double middlePosition = barTopPosition + context.convertToPainterUnits( settings.height() / 2.0, QgsUnitTypes::RenderMillimeters );
const double bottomPosition = barTopPosition + context.convertToPainterUnits( settings.height(), QgsUnitTypes::RenderMillimeters );
const double scaledSubdivisionsHeight = context.convertToPainterUnits( settings.subdivisionsHeight(), QgsUnitTypes::RenderMillimeters );

const double xOffset = firstLabelXOffset( settings, context, scaleContext );

Expand All @@ -114,13 +116,44 @@ void QgsTicksScaleBarRenderer::draw( QgsRenderContext &context, const QgsScaleBa
// we render the bar symbol-layer-by-symbol-layer, to avoid ugliness where the lines overlap in multi-layer symbols
for ( int layer = 0; layer < symbol->symbolLayerCount(); ++ layer )
{
// first draw the vertical lines
// first draw the vertical lines for segments
for ( int i = 0; i < positions.size(); ++i )
{
const double thisX = context.convertToPainterUnits( positions.at( i ), QgsUnitTypes::RenderMillimeters ) + xOffset;
symbol->renderPolyline( QPolygonF() << QPointF( thisX, barTopPosition )
<< QPointF( thisX, bottomPosition ), nullptr, context, layer );
}
// vertical positions
double verticalPos = 0.0;
QList<double> subTickPositionsY;
switch ( mTickPosition )
{
case TicksDown:
verticalPos = barTopPosition;
subTickPositionsY << verticalPos;
subTickPositionsY << verticalPos + scaledSubdivisionsHeight;
break;
case TicksMiddle:
verticalPos = middlePosition;
subTickPositionsY << verticalPos + scaledSubdivisionsHeight / 2.0;
subTickPositionsY << verticalPos - scaledSubdivisionsHeight / 2.0;
break;
case TicksUp:
verticalPos = bottomPosition;
subTickPositionsY << verticalPos;
subTickPositionsY << verticalPos - scaledSubdivisionsHeight;
break;
}
// draw the vertical lines for right subdivisions
for ( int i = settings.numberOfSegmentsLeft(); i < positions.size(); ++i )
{
for ( int j = 1; j < settings.numberOfSubdivisions(); ++j )
{
const double thisSubX = context.convertToPainterUnits( positions.at( i ) + j * scaleContext.segmentWidth / settings.numberOfSubdivisions(), QgsUnitTypes::RenderMillimeters ) + xOffset;
symbol->renderPolyline( QPolygonF() << QPointF( thisSubX, subTickPositionsY.at( 0 ) )
<< QPointF( thisSubX, subTickPositionsY.at( 1 ) ), nullptr, context, layer );
}
}

//draw last tick and horizontal line
if ( !positions.isEmpty() )
Expand All @@ -131,19 +164,7 @@ void QgsTicksScaleBarRenderer::draw( QgsRenderContext &context, const QgsScaleBa
symbol->renderPolyline( QPolygonF() << QPointF( lastTickPositionX, barTopPosition )
<< QPointF( lastTickPositionX, bottomPosition ),
nullptr, context, layer );
double verticalPos = 0.0;
switch ( mTickPosition )
{
case TicksDown:
verticalPos = barTopPosition;
break;
case TicksMiddle:
verticalPos = middlePosition;
break;
case TicksUp:
verticalPos = bottomPosition;
break;
}

//horizontal line
symbol->renderPolyline( QPolygonF() << QPointF( xOffset + context.convertToPainterUnits( positions.at( 0 ), QgsUnitTypes::RenderMillimeters ), verticalPos )
<< QPointF( lastTickPositionX, verticalPos ), nullptr, context, layer );
Expand Down

0 comments on commit a3397a8

Please sign in to comment.