Add scale method option for layout scale bars

Instead of always calculating the scale along the bottom of the
map, expose a choice of methods to the user (along bottom,
middle, top, or average of the three measurements)

For new scalebars, default to the average method, which better
handles the scenario where the scale at the top or bottom of
the map cannot be calculated (eg when the top/bottom of the map
falls just outside valid areas for the map's crs)

This fixes one of the most common scenarios which cause scale
bar widths to blow out to massive sizes

Refs #55240
This commit is contained in:
Nyall Dawson 2024-09-30 07:48:04 +10:00
parent ede5a09c69
commit 29b345e2c3
13 changed files with 440 additions and 61 deletions

View File

@ -9697,6 +9697,23 @@ Qgis.PictureFormat.__doc__ = """Picture formats.
"""
# --
Qgis.PictureFormat.baseClass = Qgis
# monkey patching scoped based enum
Qgis.ScaleCalculationMethod.HorizontalTop.__doc__ = "Calculate horizontally, across top of map"
Qgis.ScaleCalculationMethod.HorizontalMiddle.__doc__ = "Calculate horizontally, across midle of map"
Qgis.ScaleCalculationMethod.HorizontalBottom.__doc__ = "Calculate horizontally, across bottom of map"
Qgis.ScaleCalculationMethod.HorizontalAverage.__doc__ = "Calculate horizontally, using the average of the top, middle and bottom scales"
Qgis.ScaleCalculationMethod.__doc__ = """Scale calculation logic.
.. versionadded:: 3.40
* ``HorizontalTop``: Calculate horizontally, across top of map
* ``HorizontalMiddle``: Calculate horizontally, across midle of map
* ``HorizontalBottom``: Calculate horizontally, across bottom of map
* ``HorizontalAverage``: Calculate horizontally, using the average of the top, middle and bottom scales
"""
# --
Qgis.ScaleCalculationMethod.baseClass = Qgis
QgsScaleBarSettings.Alignment = Qgis.ScaleBarAlignment
# monkey patching scoped based enum
QgsScaleBarSettings.AlignLeft = Qgis.ScaleBarAlignment.Left

View File

@ -813,6 +813,24 @@ Ownership of ``format`` is transferred to the scalebar.
.. seealso:: :py:func:`numericFormat`
.. versionadded:: 3.12
%End
Qgis::ScaleCalculationMethod method() const;
%Docstring
Returns the scale calculation method, which determines how the bar's scale will be calculated.
.. seealso:: :py:func:`setMethod`
.. versionadded:: 3.40
%End
void setMethod( Qgis::ScaleCalculationMethod method );
%Docstring
Sets the scale calculation ``method``, which determines how the bar's scale will be calculated.
.. seealso:: :py:func:`method`
.. versionadded:: 3.40
%End
void update();

View File

@ -2786,6 +2786,13 @@ The development version
Unknown,
};
enum class ScaleCalculationMethod /BaseType=IntEnum/
{
HorizontalTop,
HorizontalMiddle,
HorizontalBottom,
HorizontalAverage,
};
enum class ScaleBarAlignment /BaseType=IntEnum/
{

View File

@ -9620,6 +9620,23 @@ Qgis.PictureFormat.__doc__ = """Picture formats.
"""
# --
Qgis.PictureFormat.baseClass = Qgis
# monkey patching scoped based enum
Qgis.ScaleCalculationMethod.HorizontalTop.__doc__ = "Calculate horizontally, across top of map"
Qgis.ScaleCalculationMethod.HorizontalMiddle.__doc__ = "Calculate horizontally, across midle of map"
Qgis.ScaleCalculationMethod.HorizontalBottom.__doc__ = "Calculate horizontally, across bottom of map"
Qgis.ScaleCalculationMethod.HorizontalAverage.__doc__ = "Calculate horizontally, using the average of the top, middle and bottom scales"
Qgis.ScaleCalculationMethod.__doc__ = """Scale calculation logic.
.. versionadded:: 3.40
* ``HorizontalTop``: Calculate horizontally, across top of map
* ``HorizontalMiddle``: Calculate horizontally, across midle of map
* ``HorizontalBottom``: Calculate horizontally, across bottom of map
* ``HorizontalAverage``: Calculate horizontally, using the average of the top, middle and bottom scales
"""
# --
Qgis.ScaleCalculationMethod.baseClass = Qgis
QgsScaleBarSettings.Alignment = Qgis.ScaleBarAlignment
# monkey patching scoped based enum
QgsScaleBarSettings.AlignLeft = Qgis.ScaleBarAlignment.Left

View File

@ -813,6 +813,24 @@ Ownership of ``format`` is transferred to the scalebar.
.. seealso:: :py:func:`numericFormat`
.. versionadded:: 3.12
%End
Qgis::ScaleCalculationMethod method() const;
%Docstring
Returns the scale calculation method, which determines how the bar's scale will be calculated.
.. seealso:: :py:func:`setMethod`
.. versionadded:: 3.40
%End
void setMethod( Qgis::ScaleCalculationMethod method );
%Docstring
Sets the scale calculation ``method``, which determines how the bar's scale will be calculated.
.. seealso:: :py:func:`method`
.. versionadded:: 3.40
%End
void update();

View File

@ -2786,6 +2786,13 @@ The development version
Unknown,
};
enum class ScaleCalculationMethod
{
HorizontalTop,
HorizontalMiddle,
HorizontalBottom,
HorizontalAverage,
};
enum class ScaleBarAlignment
{

View File

@ -290,6 +290,21 @@ void QgsLayoutItemScaleBar::disconnectCurrentMap()
mMap = nullptr;
}
Qgis::ScaleCalculationMethod QgsLayoutItemScaleBar::method() const
{
return mMethod;
}
void QgsLayoutItemScaleBar::setMethod( Qgis::ScaleCalculationMethod method )
{
if ( mMethod == method )
return;
mMethod = method;
refreshSegmentMillimeters();
resizeToMinimumWidth();
}
void QgsLayoutItemScaleBar::refreshUnitsPerSegment( const QgsExpressionContext *context )
{
if ( mDataDefinedProperties.isActive( QgsLayoutObject::DataDefinedProperty::ScalebarSegmentWidth ) )
@ -570,19 +585,62 @@ double QgsLayoutItemScaleBar::mapWidth() const
da.setEllipsoid( mLayout->project()->ellipsoid() );
const Qgis::DistanceUnit units = da.lengthUnits();
double measure = 0;
try
QList< double > yValues;
switch ( mMethod )
{
measure = da.measureLine( QgsPointXY( mapExtent.xMinimum(), mapExtent.yMinimum() ),
QgsPointXY( mapExtent.xMaximum(), mapExtent.yMinimum() ) );
measure /= QgsUnitTypes::fromUnitToUnitFactor( mSettings.units(), units );
case Qgis::ScaleCalculationMethod::HorizontalTop:
yValues << mapExtent.yMaximum();
break;
case Qgis::ScaleCalculationMethod::HorizontalMiddle:
yValues << 0.5 * ( mapExtent.yMaximum() + mapExtent.yMinimum() );
break;
case Qgis::ScaleCalculationMethod::HorizontalBottom:
yValues << mapExtent.yMinimum();
break;
case Qgis::ScaleCalculationMethod::HorizontalAverage:
yValues << mapExtent.yMaximum();
yValues << 0.5 * ( mapExtent.yMaximum() + mapExtent.yMinimum() );
yValues << mapExtent.yMinimum();
break;
}
catch ( QgsCsException & )
double sumValidMeasures = 0;
int validMeasureCount = 0;
for ( const double y : std::as_const( yValues ) )
{
// TODO report errors to user
QgsDebugError( QStringLiteral( "An error occurred while calculating length" ) );
try
{
double measure = da.measureLine( QgsPointXY( mapExtent.xMinimum(), y ),
QgsPointXY( mapExtent.xMaximum(), y ) );
if ( std::isnan( measure ) )
{
// TODO report errors to user
QgsDebugError( QStringLiteral( "An error occurred while calculating length" ) );
continue;
}
measure /= QgsUnitTypes::fromUnitToUnitFactor( mSettings.units(), units );
sumValidMeasures += measure;
validMeasureCount++;
}
catch ( QgsCsException & )
{
// TODO report errors to user
QgsDebugError( QStringLiteral( "An error occurred while calculating length" ) );
continue;
}
}
return measure;
if ( validMeasureCount == 0 )
return std::numeric_limits< double >::quiet_NaN();
return sumValidMeasures / validMeasureCount;
}
}
@ -965,6 +1023,7 @@ bool QgsLayoutItemScaleBar::writePropertiesToElement( QDomElement &composerScale
composerScaleBarElem.setAttribute( QStringLiteral( "maxBarWidth" ), mSettings.maximumBarWidth() );
composerScaleBarElem.setAttribute( QStringLiteral( "segmentMillimeters" ), QString::number( mSegmentMillimeters ) );
composerScaleBarElem.setAttribute( QStringLiteral( "numMapUnitsPerScaleBarUnit" ), QString::number( mSettings.mapUnitsPerScaleBarUnit() ) );
composerScaleBarElem.setAttribute( QStringLiteral( "method" ), qgsEnumValueToKey( mMethod ) );
const QDomElement textElem = mSettings.textFormat().writeXml( doc, rwContext );
composerScaleBarElem.appendChild( textElem );
@ -1092,6 +1151,9 @@ bool QgsLayoutItemScaleBar::readPropertiesFromElement( const QDomElement &itemEl
mSegmentMillimeters = itemElem.attribute( QStringLiteral( "segmentMillimeters" ), QStringLiteral( "0.0" ) ).toDouble();
mSettings.setMapUnitsPerScaleBarUnit( itemElem.attribute( QStringLiteral( "numMapUnitsPerScaleBarUnit" ), QStringLiteral( "1.0" ) ).toDouble() );
// default to horizontal bottom to keep same behavior for older projects
mMethod = qgsEnumKeyToValue( itemElem.attribute( QStringLiteral( "method" ) ), Qgis::ScaleCalculationMethod::HorizontalBottom );
const QDomElement lineSymbolElem = itemElem.firstChildElement( QStringLiteral( "lineSymbol" ) );
bool foundLineSymbol = false;
if ( !lineSymbolElem.isNull() )

View File

@ -648,6 +648,22 @@ class CORE_EXPORT QgsLayoutItemScaleBar: public QgsLayoutItem
*/
void setNumericFormat( QgsNumericFormat *format SIP_TRANSFER );
/**
* Returns the scale calculation method, which determines how the bar's scale will be calculated.
*
* \see setMethod()
* \since QGIS 3.40
*/
Qgis::ScaleCalculationMethod method() const;
/**
* Sets the scale calculation \a method, which determines how the bar's scale will be calculated.
*
* \see method()
* \since QGIS 3.40
*/
void setMethod( Qgis::ScaleCalculationMethod method );
/**
* Adjusts the scale bar box size and updates the item.
*/
@ -675,6 +691,7 @@ class CORE_EXPORT QgsLayoutItemScaleBar: public QgsLayoutItem
QString mMapUuid;
QgsScaleBarSettings mSettings;
Qgis::ScaleCalculationMethod mMethod = Qgis::ScaleCalculationMethod::HorizontalAverage;
//! Scalebar style
std::unique_ptr< QgsScaleBarRenderer > mStyle;

View File

@ -4897,6 +4897,19 @@ class CORE_EXPORT Qgis
};
Q_ENUM( PictureFormat )
/**
* Scale calculation logic.
*
* \since QGIS 3.40
*/
enum class ScaleCalculationMethod : int
{
HorizontalTop = 0, //!< Calculate horizontally, across top of map
HorizontalMiddle, //!< Calculate horizontally, across midle of map
HorizontalBottom, //!< Calculate horizontally, across bottom of map
HorizontalAverage, //!< Calculate horizontally, using the average of the top, middle and bottom scales
};
Q_ENUM( ScaleCalculationMethod )
/**
* Scalebar alignment.

View File

@ -55,6 +55,20 @@ QgsLayoutScaleBarWidget::QgsLayoutScaleBarWidget( QgsLayoutItemScaleBar *scaleBa
connect( mMinWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutScaleBarWidget::mMinWidthSpinBox_valueChanged );
connect( mMaxWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutScaleBarWidget::mMaxWidthSpinBox_valueChanged );
connect( mNumberFormatPushButton, &QPushButton::clicked, this, &QgsLayoutScaleBarWidget::changeNumberFormat );
connect( mMethodCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]
{
if ( !mScalebar )
{
return;
}
disconnectUpdateSignal();
mScalebar->beginCommand( tr( "Set Scalebar Method" ) );
mScalebar->setMethod( mMethodCombo->currentData().value< Qgis::ScaleCalculationMethod >() );
mScalebar->update();
connectUpdateSignal();
mScalebar->endCommand();
} );
registerDataDefinedButton( mSegmentsLeftDDBtn, QgsLayoutObject::DataDefinedProperty::ScalebarLeftSegments );
registerDataDefinedButton( mSegmentsRightDDBtn, QgsLayoutObject::DataDefinedProperty::ScalebarRightSegments );
@ -115,6 +129,11 @@ QgsLayoutScaleBarWidget::QgsLayoutScaleBarWidget( QgsLayoutItemScaleBar *scaleBa
mUnitsComboBox->addItem( tr( "Millimeters" ), static_cast< int >( Qgis::DistanceUnit::Millimeters ) );
mUnitsComboBox->addItem( tr( "Inches" ), static_cast< int >( Qgis::DistanceUnit::Inches ) );
mMethodCombo->addItem( tr( "Average Top, Middle and Bottom Scales" ), QVariant::fromValue( Qgis::ScaleCalculationMethod::HorizontalAverage ) );
mMethodCombo->addItem( tr( "Calculate along Top of Map" ), QVariant::fromValue( Qgis::ScaleCalculationMethod::HorizontalTop ) );
mMethodCombo->addItem( tr( "Calculate along Middle of Map" ), QVariant::fromValue( Qgis::ScaleCalculationMethod::HorizontalMiddle ) );
mMethodCombo->addItem( tr( "Calculate along Bottom of Map" ), QVariant::fromValue( Qgis::ScaleCalculationMethod::HorizontalBottom ) );
mLineStyleButton->setSymbolType( Qgis::SymbolType::Line );
connect( mLineStyleButton, &QgsSymbolButton::changed, this, &QgsLayoutScaleBarWidget::lineSymbolChanged );
@ -349,6 +368,8 @@ void QgsLayoutScaleBarWidget::setGuiElements()
mMinWidthSpinBox->setValue( mScalebar->minimumBarWidth() );
mMaxWidthSpinBox->setValue( mScalebar->maximumBarWidth() );
mMethodCombo->setCurrentIndex( mMethodCombo->findData( QVariant::fromValue( mScalebar->method() ) ) );
populateDataDefinedButtons();
blockMemberSignals( false );
@ -745,6 +766,7 @@ void QgsLayoutScaleBarWidget::blockMemberSignals( bool block )
mFontButton->blockSignals( block );
mMinWidthSpinBox->blockSignals( block );
mMaxWidthSpinBox->blockSignals( block );
mMethodCombo->blockSignals( block );
}
void QgsLayoutScaleBarWidget::connectUpdateSignal()

View File

@ -62,14 +62,14 @@
<x>0</x>
<y>0</y>
<width>566</width>
<height>1018</height>
<height>1031</height>
</rect>
</property>
<layout class="QVBoxLayout" name="mainLayout">
<item>
<widget class="QgsCollapsibleGroupBoxBasic" name="groupBox">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
<enum>Qt::FocusPolicy::StrongFocus</enum>
</property>
<property name="title">
<string>Main Properties</string>
@ -122,7 +122,7 @@
<item>
<widget class="QgsCollapsibleGroupBoxBasic" name="mGroupBoxUnits">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
<enum>Qt::FocusPolicy::StrongFocus</enum>
</property>
<property name="title">
<string>Units</string>
@ -134,10 +134,54 @@
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,0">
<item row="2" column="0">
<widget class="QLabel" name="mUnitLabelLabel">
<item row="2" column="1">
<widget class="QLineEdit" name="mUnitLabelLineEdit">
<property name="toolTip">
<string>Text used for labeling the scalebar units, e.g., &quot;m&quot; or &quot;km&quot;. This should be matched to reflect the multiplier above.</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="mNumberFormatPushButton">
<property name="text">
<string>&amp;Label for units</string>
<string>Customize</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="mUnitsComboBox">
<property name="toolTip">
<string>Specifies the underlying units used for scalebar calculations, e.g., &quot;meters&quot; or &quot;feet&quot;</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QgsDoubleSpinBox" name="mMapUnitsPerBarUnitSpinBox">
<property name="toolTip">
<string>Specifies how many scalebar units per labeled unit. For example, if your scalebar units are set to &quot;meters&quot;, a multiplier of 1000 will result in the scalebar labels in kilometers.</string>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="maximum">
<double>9999999999999.000000000000000</double>
</property>
<property name="showClearButton" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="mUnitsLabel">
<property name="text">
<string>Scalebar units</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="mUnitLabelLabel_2">
<property name="text">
<string>Number format</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@ -160,47 +204,10 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QgsDoubleSpinBox" name="mMapUnitsPerBarUnitSpinBox">
<property name="toolTip">
<string>Specifies how many scalebar units per labeled unit. For example, if your scalebar units are set to &quot;meters&quot;, a multiplier of 1000 will result in the scalebar labels in kilometers.</string>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="maximum">
<double>9999999999999.000000000000000</double>
</property>
<property name="showClearButton">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="mUnitsComboBox">
<property name="toolTip">
<string>Specifies the underlying units used for scalebar calculations, e.g., &quot;meters&quot; or &quot;feet&quot;</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="mUnitsLabel">
<item row="2" column="0">
<widget class="QLabel" name="mUnitLabelLabel">
<property name="text">
<string>Scalebar units</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="mUnitLabelLineEdit">
<property name="toolTip">
<string>Text used for labeling the scalebar units, e.g., &quot;m&quot; or &quot;km&quot;. This should be matched to reflect the multiplier above.</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="mUnitLabelLabel_2">
<property name="text">
<string>Number format</string>
<string>&amp;Label for units</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@ -210,10 +217,13 @@
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="mNumberFormatPushButton">
<item row="4" column="1">
<widget class="QComboBox" name="mMethodCombo"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Customize</string>
<string>Method</string>
</property>
</widget>
</item>
@ -223,7 +233,7 @@
<item>
<widget class="QgsCollapsibleGroupBoxBasic" name="mGroupBoxSegments">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
<enum>Qt::FocusPolicy::StrongFocus</enum>
</property>
<property name="title">
<string>Segments</string>
@ -505,7 +515,7 @@
<property name="maximum">
<double>9999999999999.000000000000000</double>
</property>
<property name="showClearButton">
<property name="showClearButton" stdset="0">
<bool>false</bool>
</property>
</widget>
@ -526,7 +536,7 @@
<item>
<widget class="QgsCollapsibleGroupBoxBasic" name="groupBox_5">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
<enum>Qt::FocusPolicy::StrongFocus</enum>
</property>
<property name="title">
<string>Appearance</string>
@ -782,6 +792,7 @@
<tabstop>mMapUnitsPerBarUnitSpinBox</tabstop>
<tabstop>mUnitLabelLineEdit</tabstop>
<tabstop>mNumberFormatPushButton</tabstop>
<tabstop>mMethodCombo</tabstop>
<tabstop>mGroupBoxSegments</tabstop>
<tabstop>mSegmentsLeftSpinBox</tabstop>
<tabstop>mSegmentsLeftDDBtn</tabstop>

View File

@ -65,6 +65,7 @@ class TestQgsLayoutScaleBar : public QgsTest
void hollow();
void hollowDefaults();
void tickSubdivisions();
void methodTop();
};
void TestQgsLayoutScaleBar::initTestCase()
@ -906,6 +907,175 @@ void TestQgsLayoutScaleBar::tickSubdivisions()
QGSVERIFYLAYOUTCHECK( QStringLiteral( "layoutscalebar_tick_subdivisions" ), &l );
}
void TestQgsLayoutScaleBar::methodTop()
{
QgsLayout l( QgsProject::instance() );
l.initializeDefaults();
QgsLayoutItemMap *map1 = new QgsLayoutItemMap( &l );
map1->attemptSetSceneRect( QRectF( 20, 20, 150, 150 ) );
map1->setFrameEnabled( false );
map1->setVisibility( false );
l.addLayoutItem( map1 );
// only scale at center of map can be calculated
map1->setExtent( QgsRectangle( -100, -100, 100, 100 ) );
map1->setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
QgsLayoutItemScaleBar *scalebar1 = new QgsLayoutItemScaleBar( &l );
scalebar1->attemptSetSceneRect( QRectF( 20, 10, 50, 20 ) );
l.addLayoutItem( scalebar1 );
scalebar1->setLinkedMap( map1 );
scalebar1->setTextFormat( QgsTextFormat::fromQFont( QgsFontUtils::getStandardTestFont() ) );
scalebar1->setUnits( Qgis::DistanceUnit::Kilometers );
scalebar1->setUnitsPerSegment( 10000 );
scalebar1->setNumberOfSegmentsLeft( 0 );
scalebar1->setNumberOfSegments( 2 );
scalebar1->setHeight( 5 );
scalebar1->setSubdivisionsHeight( 25 ); //ensure subdivisionsHeight is non used in non tick-style scalebars
scalebar1->setMethod( Qgis::ScaleCalculationMethod::HorizontalMiddle );
Q_NOWARN_DEPRECATED_PUSH
scalebar1->setLineWidth( 1.0 );
Q_NOWARN_DEPRECATED_POP
qgis::down_cast< QgsBasicNumericFormat *>( const_cast< QgsNumericFormat * >( scalebar1->numericFormat() ) )->setShowThousandsSeparator( false );
scalebar1->setStyle( QStringLiteral( "Single Box" ) );
QgsLayoutItemScaleBar *scalebar1A = new QgsLayoutItemScaleBar( &l );
scalebar1A->attemptSetSceneRect( QRectF( 20, 30, 50, 20 ) );
l.addLayoutItem( scalebar1A );
scalebar1A->setLinkedMap( map1 );
scalebar1A->setTextFormat( QgsTextFormat::fromQFont( QgsFontUtils::getStandardTestFont() ) );
scalebar1A->setUnits( Qgis::DistanceUnit::Kilometers );
scalebar1A->setUnitsPerSegment( 10000 );
scalebar1A->setNumberOfSegmentsLeft( 0 );
scalebar1A->setNumberOfSegments( 2 );
scalebar1A->setHeight( 5 );
scalebar1A->setSubdivisionsHeight( 25 ); //ensure subdivisionsHeight is non used in non tick-style scalebars
scalebar1A->setMethod( Qgis::ScaleCalculationMethod::HorizontalAverage );
Q_NOWARN_DEPRECATED_PUSH
scalebar1A->setLineWidth( 1.0 );
Q_NOWARN_DEPRECATED_POP
qgis::down_cast< QgsBasicNumericFormat *>( const_cast< QgsNumericFormat * >( scalebar1A->numericFormat() ) )->setShowThousandsSeparator( false );
scalebar1A->setStyle( QStringLiteral( "Single Box" ) );
QgsLayoutItemMap *map2 = new QgsLayoutItemMap( &l );
map2->attemptSetSceneRect( QRectF( 20, 20, 150, 150 ) );
map2->setFrameEnabled( false );
map2->setVisibility( false );
l.addLayoutItem( map2 );
// only scale at top of map can be calculated
map2->setExtent( QgsRectangle( -100, -280, 100, -80 ) );
map2->setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
QgsLayoutItemScaleBar *scalebar2 = new QgsLayoutItemScaleBar( &l );
scalebar2->attemptSetSceneRect( QRectF( 20, 50, 50, 20 ) );
l.addLayoutItem( scalebar2 );
scalebar2->setLinkedMap( map2 );
scalebar2->setTextFormat( QgsTextFormat::fromQFont( QgsFontUtils::getStandardTestFont() ) );
scalebar2->setUnits( Qgis::DistanceUnit::Kilometers );
scalebar2->setUnitsPerSegment( 1000 );
scalebar2->setNumberOfSegmentsLeft( 0 );
scalebar2->setNumberOfSegments( 2 );
scalebar2->setHeight( 5 );
scalebar2->setSubdivisionsHeight( 25 ); //ensure subdivisionsHeight is non used in non tick-style scalebars
scalebar2->setMethod( Qgis::ScaleCalculationMethod::HorizontalTop );
Q_NOWARN_DEPRECATED_PUSH
scalebar2->setLineWidth( 1.0 );
Q_NOWARN_DEPRECATED_POP
qgis::down_cast< QgsBasicNumericFormat *>( const_cast< QgsNumericFormat * >( scalebar2->numericFormat() ) )->setShowThousandsSeparator( false );
scalebar2->setStyle( QStringLiteral( "Single Box" ) );
QgsLayoutItemScaleBar *scalebar2A = new QgsLayoutItemScaleBar( &l );
scalebar2A->attemptSetSceneRect( QRectF( 20, 70, 50, 20 ) );
l.addLayoutItem( scalebar2A );
scalebar2A->setLinkedMap( map2 );
scalebar2A->setTextFormat( QgsTextFormat::fromQFont( QgsFontUtils::getStandardTestFont() ) );
scalebar2A->setUnits( Qgis::DistanceUnit::Kilometers );
scalebar2A->setUnitsPerSegment( 1000 );
scalebar2A->setNumberOfSegmentsLeft( 0 );
scalebar2A->setNumberOfSegments( 2 );
scalebar2A->setHeight( 5 );
scalebar2A->setSubdivisionsHeight( 25 ); //ensure subdivisionsHeight is non used in non tick-style scalebars
scalebar2A->setMethod( Qgis::ScaleCalculationMethod::HorizontalAverage );
Q_NOWARN_DEPRECATED_PUSH
scalebar2A->setLineWidth( 1.0 );
Q_NOWARN_DEPRECATED_POP
qgis::down_cast< QgsBasicNumericFormat *>( const_cast< QgsNumericFormat * >( scalebar2A->numericFormat() ) )->setShowThousandsSeparator( false );
scalebar2A->setStyle( QStringLiteral( "Single Box" ) );
QgsLayoutItemMap *map3 = new QgsLayoutItemMap( &l );
map3->attemptSetSceneRect( QRectF( 20, 90, 150, 150 ) );
map3->setFrameEnabled( false );
map3->setVisibility( false );
l.addLayoutItem( map3 );
// only scale at bottom of map can be calculated
map3->setExtent( QgsRectangle( -100, 80, 100, 280 ) );
map3->setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
QgsLayoutItemScaleBar *scalebar3 = new QgsLayoutItemScaleBar( &l );
scalebar3->attemptSetSceneRect( QRectF( 20, 90, 50, 20 ) );
l.addLayoutItem( scalebar3 );
scalebar3->setLinkedMap( map3 );
scalebar3->setTextFormat( QgsTextFormat::fromQFont( QgsFontUtils::getStandardTestFont() ) );
scalebar3->setUnits( Qgis::DistanceUnit::Kilometers );
scalebar3->setUnitsPerSegment( 1000 );
scalebar3->setNumberOfSegmentsLeft( 0 );
scalebar3->setNumberOfSegments( 2 );
scalebar3->setHeight( 5 );
scalebar3->setSubdivisionsHeight( 25 ); //ensure subdivisionsHeight is non used in non tick-style scalebars
scalebar3->setMethod( Qgis::ScaleCalculationMethod::HorizontalBottom );
Q_NOWARN_DEPRECATED_PUSH
scalebar3->setLineWidth( 1.0 );
Q_NOWARN_DEPRECATED_POP
qgis::down_cast< QgsBasicNumericFormat *>( const_cast< QgsNumericFormat * >( scalebar3->numericFormat() ) )->setShowThousandsSeparator( false );
scalebar3->setStyle( QStringLiteral( "Single Box" ) );
QgsLayoutItemScaleBar *scalebar3A = new QgsLayoutItemScaleBar( &l );
scalebar3A->attemptSetSceneRect( QRectF( 20, 110, 50, 20 ) );
l.addLayoutItem( scalebar3A );
scalebar3A->setLinkedMap( map3 );
scalebar3A->setTextFormat( QgsTextFormat::fromQFont( QgsFontUtils::getStandardTestFont() ) );
scalebar3A->setUnits( Qgis::DistanceUnit::Kilometers );
scalebar3A->setUnitsPerSegment( 1000 );
scalebar3A->setNumberOfSegmentsLeft( 0 );
scalebar3A->setNumberOfSegments( 2 );
scalebar3A->setHeight( 5 );
scalebar3A->setSubdivisionsHeight( 25 ); //ensure subdivisionsHeight is non used in non tick-style scalebars
scalebar3A->setMethod( Qgis::ScaleCalculationMethod::HorizontalAverage );
Q_NOWARN_DEPRECATED_PUSH
scalebar3A->setLineWidth( 1.0 );
Q_NOWARN_DEPRECATED_POP
qgis::down_cast< QgsBasicNumericFormat *>( const_cast< QgsNumericFormat * >( scalebar3A->numericFormat() ) )->setShowThousandsSeparator( false );
scalebar3A->setStyle( QStringLiteral( "Single Box" ) );
QgsLayoutItemMap *map4 = new QgsLayoutItemMap( &l );
map4->attemptSetSceneRect( QRectF( 20, 90, 150, 150 ) );
map4->setFrameEnabled( false );
map4->setVisibility( false );
l.addLayoutItem( map4 );
// scale is valid everywhere
map4->setExtent( QgsRectangle( -80, -80, 80, 80 ) );
map4->setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
QgsLayoutItemScaleBar *scalebar4 = new QgsLayoutItemScaleBar( &l );
scalebar4->attemptSetSceneRect( QRectF( 20, 130, 50, 20 ) );
l.addLayoutItem( scalebar4 );
scalebar4->setLinkedMap( map4 );
scalebar4->setTextFormat( QgsTextFormat::fromQFont( QgsFontUtils::getStandardTestFont() ) );
scalebar4->setUnits( Qgis::DistanceUnit::Kilometers );
scalebar4->setUnitsPerSegment( 5000 );
scalebar4->setNumberOfSegmentsLeft( 0 );
scalebar4->setNumberOfSegments( 2 );
scalebar4->setHeight( 5 );
scalebar4->setSubdivisionsHeight( 25 ); //ensure subdivisionsHeight is non used in non tick-style scalebars
scalebar4->setMethod( Qgis::ScaleCalculationMethod::HorizontalAverage );
Q_NOWARN_DEPRECATED_PUSH
scalebar4->setLineWidth( 1.0 );
Q_NOWARN_DEPRECATED_POP
qgis::down_cast< QgsBasicNumericFormat *>( const_cast< QgsNumericFormat * >( scalebar4->numericFormat() ) )->setShowThousandsSeparator( false );
scalebar4->setStyle( QStringLiteral( "Single Box" ) );
QGSVERIFYLAYOUTCHECK( QStringLiteral( "scalebar_method" ), &l );
}
QGSTEST_MAIN( TestQgsLayoutScaleBar )
#include "testqgslayoutscalebar.moc"

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB