Skip to content

Commit

Permalink
Allow setting distance unit for layout elevation profile items
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed May 29, 2023
1 parent bb5cfb8 commit ae638d2
Show file tree
Hide file tree
Showing 8 changed files with 357 additions and 69 deletions.
Expand Up @@ -152,6 +152,24 @@ Returns the profile request used to generate the elevation profile.
virtual void paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget );


Qgis::DistanceUnit distanceUnit() const;
%Docstring
Returns the units for the distance axis.

.. seealso:: :py:func:`setDistanceUnit`

.. versionadded:: 3.32
%End

void setDistanceUnit( Qgis::DistanceUnit unit );
%Docstring
Sets the ``unit`` for the distance axis.

.. seealso:: :py:func:`distanceUnit`

.. versionadded:: 3.32
%End

public slots:

virtual void refresh();
Expand Down
50 changes: 47 additions & 3 deletions src/core/layout/qgslayoutitemelevationprofile.cpp
Expand Up @@ -55,11 +55,13 @@ class QgsLayoutItemElevationProfilePlot : public Qgs2DPlot
if ( mRenderer )
{
rc.painter()->translate( plotArea.left(), plotArea.top() );
mRenderer->render( rc, plotArea.width(), plotArea.height(), xMinimum(), xMaximum(), yMinimum(), yMaximum() );
mRenderer->render( rc, plotArea.width(), plotArea.height(), xMinimum() * xScale, xMaximum() * xScale, yMinimum(), yMaximum() );
rc.painter()->translate( -plotArea.left(), -plotArea.top() );
}
}

double xScale = 1;

private:

QgsProfilePlotRenderer *mRenderer = nullptr;
Expand Down Expand Up @@ -641,7 +643,9 @@ void QgsLayoutItemElevationProfile::paint( QPainter *painter, const QStyleOption
layoutSize *= dotsPerMM; // output size will be in dots (pixels)
painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots

const double mapUnitsPerPixel = static_cast<double>( mPlot->xMaximum() - mPlot->xMinimum() ) / layoutSize.width();
mPlot->xScale = QgsUnitTypes::fromUnitToUnitFactor( mDistanceUnit, mCrs.mapUnits() );

const double mapUnitsPerPixel = static_cast<double>( mPlot->xMaximum() - mPlot->xMinimum() ) * mPlot->xScale / layoutSize.width();
rc.setMapToPixel( QgsMapToPixel( mapUnitsPerPixel ) );

QList< QgsAbstractProfileSource * > sources;
Expand All @@ -653,6 +657,7 @@ void QgsLayoutItemElevationProfile::paint( QPainter *painter, const QStyleOption

QgsProfilePlotRenderer renderer( sources, profileRequest() );


// TODO
// we should be able to call renderer.start()/renderer.waitForFinished() here and
// benefit from parallel source generation. BUT
Expand Down Expand Up @@ -722,6 +727,8 @@ bool QgsLayoutItemElevationProfile::writePropertiesToElement( QDomElement &layou
layoutProfileElem.appendChild( plotElement );
}

layoutProfileElem.setAttribute( QStringLiteral( "distanceUnit" ), qgsEnumValueToKey( mDistanceUnit ) );

layoutProfileElem.setAttribute( QStringLiteral( "tolerance" ), mTolerance );
layoutProfileElem.setAttribute( QStringLiteral( "atlasDriven" ), mAtlasDriven ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
if ( mCrs.isValid() )
Expand Down Expand Up @@ -768,6 +775,8 @@ bool QgsLayoutItemElevationProfile::readPropertiesFromElement( const QDomElement
}
mCrs = crs;

setDistanceUnit( qgsEnumKeyToValue( itemElem.attribute( QStringLiteral( "distanceUnit" ) ), mCrs.mapUnits() ) );

const QDomNodeList curveNodeList = itemElem.elementsByTagName( QStringLiteral( "curve" ) );
if ( !curveNodeList.isEmpty() )
{
Expand Down Expand Up @@ -892,7 +901,9 @@ void QgsLayoutItemElevationProfile::profileGenerationFinished()

QgsRenderContext rc = QgsLayoutUtils::createRenderContextForLayout( mLayout, mPainter.get() );

const double mapUnitsPerPixel = static_cast< double >( mPlot->xMaximum() - mPlot->xMinimum() ) /
mPlot->xScale = QgsUnitTypes::fromUnitToUnitFactor( mDistanceUnit, mCrs.mapUnits() );

const double mapUnitsPerPixel = static_cast< double >( mPlot->xMaximum() - mPlot->xMinimum() ) * mPlot->xScale /
mCacheRenderingImage->size().width();
rc.setMapToPixel( QgsMapToPixel( mapUnitsPerPixel ) );

Expand All @@ -911,3 +922,36 @@ void QgsLayoutItemElevationProfile::profileGenerationFinished()
update();
}

Qgis::DistanceUnit QgsLayoutItemElevationProfile::distanceUnit() const
{
return mDistanceUnit;
}

void QgsLayoutItemElevationProfile::setDistanceUnit( Qgis::DistanceUnit unit )
{
mDistanceUnit = unit;

switch ( mDistanceUnit )
{
case Qgis::DistanceUnit::Meters:
case Qgis::DistanceUnit::Kilometers:
case Qgis::DistanceUnit::Feet:
case Qgis::DistanceUnit::NauticalMiles:
case Qgis::DistanceUnit::Yards:
case Qgis::DistanceUnit::Miles:
case Qgis::DistanceUnit::Centimeters:
case Qgis::DistanceUnit::Millimeters:
case Qgis::DistanceUnit::Inches:
mPlot->xAxis().setLabelSuffix( QgsUnitTypes::toAbbreviatedString( mDistanceUnit ) );
break;

case Qgis::DistanceUnit::Degrees:
mPlot->xAxis().setLabelSuffix( QObject::tr( "°" ) );
break;

case Qgis::DistanceUnit::Unknown:
mPlot->xAxis().setLabelSuffix( QString() );
break;
}
}

17 changes: 17 additions & 0 deletions src/core/layout/qgslayoutitemelevationprofile.h
Expand Up @@ -167,6 +167,22 @@ class CORE_EXPORT QgsLayoutItemElevationProfile: public QgsLayoutItem

void paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget ) override;

/**
* Returns the units for the distance axis.
*
* \see setDistanceUnit()
* \since QGIS 3.32
*/
Qgis::DistanceUnit distanceUnit() const;

/**
* Sets the \a unit for the distance axis.
*
* \see distanceUnit()
* \since QGIS 3.32
*/
void setDistanceUnit( Qgis::DistanceUnit unit );

public slots:

void refresh() override;
Expand All @@ -188,6 +204,7 @@ class CORE_EXPORT QgsLayoutItemElevationProfile: public QgsLayoutItem
QList< QgsMapLayerRef > mLayers;

QgsCoordinateReferenceSystem mCrs;
Qgis::DistanceUnit mDistanceUnit = Qgis::DistanceUnit::Unknown;
std::unique_ptr< QgsCurve> mCurve;
bool mAtlasDriven = false;

Expand Down
2 changes: 1 addition & 1 deletion src/gui/elevation/qgselevationprofilecanvas.cpp
Expand Up @@ -227,7 +227,7 @@ class QgsElevationProfilePlotItem : public Qgs2DPlot, public QgsPlotCanvasItem
}

QgsProject *mProject = nullptr;
double mXScaleFactor = 1.0 / 1000;
double mXScaleFactor = 1.0;

Qgis::DistanceUnit mDistanceUnit = Qgis::DistanceUnit::Unknown;

Expand Down
66 changes: 66 additions & 0 deletions src/gui/layout/qgslayoutelevationprofilewidget.cpp
Expand Up @@ -32,6 +32,7 @@
#include "qgscurve.h"
#include "qgslayoutatlas.h"
#include "qgslayoutreportcontext.h"
#include "qgsgui.h"
#include <QMenu>

std::function< void( QgsLayoutElevationProfileWidget *, QMenu * ) > QgsLayoutElevationProfileWidget::sBuildCopyMenuFunction = []( QgsLayoutElevationProfileWidget *, QMenu * ) {};
Expand Down Expand Up @@ -437,6 +438,62 @@ QgsLayoutElevationProfileWidget::QgsLayoutElevationProfileWidget( QgsLayoutItemE
mProfile->endCommand();
} );

for ( Qgis::DistanceUnit unit :
{
Qgis::DistanceUnit::Kilometers,
Qgis::DistanceUnit::Meters,
Qgis::DistanceUnit::Centimeters,
Qgis::DistanceUnit::Millimeters,
Qgis::DistanceUnit::Miles,
Qgis::DistanceUnit::NauticalMiles,
Qgis::DistanceUnit::Yards,
Qgis::DistanceUnit::Feet,
Qgis::DistanceUnit::Inches,
Qgis::DistanceUnit::Degrees,
} )
{
QString title;
if ( ( QgsGui::higFlags() & QgsGui::HigDialogTitleIsTitleCase ) )
{
title = QgsStringUtils::capitalize( QgsUnitTypes::toString( unit ), Qgis::Capitalization::TitleCase );
}
else
{
title = QgsUnitTypes::toString( unit );
}
mDistanceUnitCombo->addItem( title, QVariant::fromValue( unit ) );
}

connect( mDistanceUnitCombo, qOverload< int >( &QComboBox::currentIndexChanged ), this, [ = ]( int )
{
if ( !mProfile || mBlockChanges )
return;

mProfile->beginCommand( tr( "Change Profile Chart Units" ) );
mProfile->setDistanceUnit( mDistanceUnitCombo->currentData().value< Qgis::DistanceUnit >() );
mProfile->invalidateCache();
mProfile->update();
mProfile->endCommand();
} );

mDistanceLabelsCombo->addItem( tr( "None" ), QVariant::fromValue( Qgis::PlotAxisSuffixPlacement::NoLabels ) );
mDistanceLabelsCombo->addItem( tr( "Every Value" ), QVariant::fromValue( Qgis::PlotAxisSuffixPlacement::EveryLabel ) );
mDistanceLabelsCombo->addItem( tr( "First Value" ), QVariant::fromValue( Qgis::PlotAxisSuffixPlacement::FirstLabel ) );
mDistanceLabelsCombo->addItem( tr( "Last Value" ), QVariant::fromValue( Qgis::PlotAxisSuffixPlacement::LastLabel ) );
mDistanceLabelsCombo->addItem( tr( "First and Last Values" ), QVariant::fromValue( Qgis::PlotAxisSuffixPlacement::FirstAndLastLabels ) );
connect( mDistanceLabelsCombo, qOverload< int >( &QComboBox::currentIndexChanged ), this, [ = ]( int )
{
if ( !mProfile || mBlockChanges )
return;

mProfile->beginCommand( tr( "Change Profile Chart Label Placement" ) );
mProfile->plot()->xAxis().setLabelSuffixPlacement( mDistanceLabelsCombo->currentData().value< Qgis::PlotAxisSuffixPlacement >() );
mProfile->invalidateCache();
mProfile->update();
mProfile->endCommand();
} );


registerDataDefinedButton( mDDBtnTolerance, QgsLayoutObject::ElevationProfileTolerance );
registerDataDefinedButton( mDDBtnMinDistance, QgsLayoutObject::ElevationProfileMinimumDistance );
registerDataDefinedButton( mDDBtnMaxDistance, QgsLayoutObject::ElevationProfileMaximumDistance );
Expand Down Expand Up @@ -542,6 +599,12 @@ void QgsLayoutElevationProfileWidget::copySettingsFromProfileCanvas( QgsElevatio
mSpinTolerance->setValue( canvas->tolerance() );
mProfile->setTolerance( canvas->tolerance() );

mProfile->setDistanceUnit( canvas->distanceUnit() );
mDistanceUnitCombo->setCurrentIndex( mDistanceUnitCombo->findData( QVariant::fromValue( canvas->distanceUnit() ) ) );

mProfile->plot()->xAxis().setLabelSuffixPlacement( canvas->plot().xAxis().labelSuffixPlacement() );
mDistanceLabelsCombo->setCurrentIndex( mDistanceLabelsCombo->findData( QVariant::fromValue( canvas->plot().xAxis().labelSuffixPlacement() ) ) );

if ( const QgsCurve *curve = canvas->profileCurve() )
mProfile->setProfileCurve( curve->clone() );

Expand Down Expand Up @@ -656,6 +719,9 @@ void QgsLayoutElevationProfileWidget::setGuiElementValues()
mDistanceAxisLabelFontButton->setTextFormat( mProfile->plot()->xAxis().textFormat() );
mElevationAxisLabelFontButton->setTextFormat( mProfile->plot()->yAxis().textFormat() );

mDistanceUnitCombo->setCurrentIndex( mDistanceUnitCombo->findData( QVariant::fromValue( mProfile->distanceUnit() ) ) );
mDistanceLabelsCombo->setCurrentIndex( mDistanceLabelsCombo->findData( QVariant::fromValue( mProfile->plot()->xAxis().labelSuffixPlacement() ) ) );

mDistanceAxisMajorIntervalSpin->setValue( mProfile->plot()->xAxis().gridIntervalMajor() );
mDistanceAxisMinorIntervalSpin->setValue( mProfile->plot()->xAxis().gridIntervalMinor() );
mDistanceAxisLabelIntervalSpin->setValue( mProfile->plot()->xAxis().labelInterval() );
Expand Down

0 comments on commit ae638d2

Please sign in to comment.