Add QgsMapSettings::computeExtentForScale and QgsMapSettings::computeScaleForExtent

This commit is contained in:
Sandro Mani 2019-04-04 11:26:57 +02:00
parent 19eaec7436
commit 73c61b6e25
4 changed files with 122 additions and 0 deletions

View File

@ -664,6 +664,39 @@ transform rectangle from output CRS to layer's CRS
Returns the coordinate transform from layer's CRS to destination CRS Returns the coordinate transform from layer's CRS to destination CRS
:return: transform - may be invalid if the transform is not needed :return: transform - may be invalid if the transform is not needed
%End
QgsRectangle computeExtentForScale( const QgsPointXY &center, double scale ) const;
%Docstring
Compute the extent such that its ``center`` is at the specified
position (mapped to the destinatonCrs) and the zoom factor corresponds
to the specified ``scale``
:param center: the center, in map coordinates
:param scale: the desired zoom factor (the x part of 1:x)
:return: an extent which can be passed to :py:class:`QgsMapCanvas`.setExtent
.. seealso:: :py:func:`computeScaleForExtent`
.. versionadded:: 3.22
%End
double computeScaleForExtent( const QgsRectangle &extent ) const;
%Docstring
Compute the scale that corresponds to the specified ``extent``
:param extent: the extent, as passed to :py:func:`QgsMapCanvas.setExtent`
:return: the scale denominator
.. seealso:: :py:func:`computeExtentForScale`
.. note::
This function does not consider any map rotation
.. versionadded:: 3.22
%End %End
QgsRectangle fullExtent() const; QgsRectangle fullExtent() const;

View File

@ -436,6 +436,39 @@ QgsCoordinateTransform QgsMapSettings::layerTransform( const QgsMapLayer *layer
return QgsCoordinateTransform( layer->crs(), mDestCRS, mTransformContext ); return QgsCoordinateTransform( layer->crs(), mDestCRS, mTransformContext );
} }
QgsRectangle QgsMapSettings::computeExtentForScale( const QgsPointXY &center, double scale ) const
{
// Output width in inches
const double outputWidthInInches = outputSize().width() / outputDpi();
// Desired visible width (honouring scale)
double scaledWidthInInches = outputWidthInInches * scale;
if ( mapUnits() == QgsUnitTypes::DistanceDegrees )
{
// Start with some fraction of the current extent around the center
double delta = mExtent.width() / 100.;
QgsRectangle ext( center.x() - delta, center.y() - delta, center.x() + delta, center.y() + delta );
// Get scale at extent, and then scale extent to the desired scale
double testScale = mScaleCalculator.calculate( ext, outputSize().width() );
ext.scale( scale / testScale );
return ext;
}
else
{
// Conversion from inches to mapUnits - this is safe to use, because we know here that the map units AREN'T in degrees
double conversionFactor = QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::DistanceFeet, mapUnits() ) / 12;
double delta = 0.5 * scaledWidthInInches * conversionFactor;
return QgsRectangle( center.x() - delta, center.y() - delta, center.x() + delta, center.y() + delta );
}
}
double QgsMapSettings::computeScaleForExtent( const QgsRectangle &extent ) const
{
return mScaleCalculator.calculate( extent, outputSize().width() );
}
double QgsMapSettings::layerToMapUnits( const QgsMapLayer *layer, const QgsRectangle &referenceExtent ) const double QgsMapSettings::layerToMapUnits( const QgsMapLayer *layer, const QgsRectangle &referenceExtent ) const
{ {
return layerTransform( layer ).scaleFactor( referenceExtent ); return layerTransform( layer ).scaleFactor( referenceExtent );

View File

@ -600,6 +600,28 @@ class CORE_EXPORT QgsMapSettings : public QgsTemporalRangeObject
*/ */
QgsCoordinateTransform layerTransform( const QgsMapLayer *layer ) const; QgsCoordinateTransform layerTransform( const QgsMapLayer *layer ) const;
/**
* \brief Compute the extent such that its \a center is at the specified
* position (mapped to the destinatonCrs) and the zoom factor corresponds
* to the specified \a scale
* \param center the center, in map coordinates
* \param scale the desired zoom factor (the x part of 1:x)
* \returns an extent which can be passed to QgsMapCanvas::setExtent
* \see computeScaleForExtent()
* \since QGIS 3.22
*/
QgsRectangle computeExtentForScale( const QgsPointXY &center, double scale ) const;
/**
* \brief Compute the scale that corresponds to the specified \a extent
* \param extent the extent, as passed to \see QgsMapCanvas::setExtent
* \returns the scale denominator
* \see computeExtentForScale()
* \note This function does not consider any map rotation
* \since QGIS 3.22
*/
double computeScaleForExtent( const QgsRectangle &extent ) const;
//! returns current extent of layer set //! returns current extent of layer set
QgsRectangle fullExtent() const; QgsRectangle fullExtent() const;

View File

@ -62,6 +62,8 @@ class TestQgsMapSettings: public QObject
void testRenderedFeatureHandlers(); void testRenderedFeatureHandlers();
void testCustomRenderingFlags(); void testCustomRenderingFlags();
void testClippingRegions(); void testClippingRegions();
void testComputeExtentForScale();
void testComputeScaleForExtent();
private: private:
QString toString( const QPolygonF &p, int decimalPlaces = 2 ) const; QString toString( const QPolygonF &p, int decimalPlaces = 2 ) const;
@ -624,5 +626,37 @@ void TestQgsMapSettings::testClippingRegions()
QCOMPARE( settings.clippingRegions().at( 0 ).geometry().asWkt(), QStringLiteral( "Polygon ((10 0, 11 0, 11 1, 10 1, 10 0))" ) ) ; QCOMPARE( settings.clippingRegions().at( 0 ).geometry().asWkt(), QStringLiteral( "Polygon ((10 0, 11 0, 11 1, 10 1, 10 0))" ) ) ;
} }
void TestQgsMapSettings::testComputeExtentForScale()
{
QgsMapSettings settings;
settings.setExtent( QgsRectangle( -500., -500., 500., 500. ) ); // Just to ensure settings are valid
settings.setDestinationCrs( QgsCoordinateReferenceSystem( "EPSG:3857" ) );
settings.setOutputSize( QSize( 1000, 1000 ) );
QgsRectangle rect = settings.computeExtentForScale( QgsPoint( 0, 0 ), 500 );
// [ output width in inches ] * [scale]
double widthInches = settings.outputSize().width() / double( settings.outputDpi() ) * 500;
double widthMapUnits = widthInches * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::DistanceFeet, settings.mapUnits() ) / 12;
QGSCOMPARENEARRECTANGLE( rect, QgsRectangle( - 0.5 * widthMapUnits, - 0.5 * widthMapUnits, 0.5 * widthMapUnits, 0.5 * widthMapUnits ), 0.0001 );
}
void TestQgsMapSettings::testComputeScaleForExtent()
{
QgsMapSettings settings;
settings.setExtent( QgsRectangle( -500., -500., 500., 500. ) ); // Just to ensure settings are valid
settings.setDestinationCrs( QgsCoordinateReferenceSystem( "EPSG:3857" ) );
settings.setOutputSize( QSize( 1000, 1000 ) );
double scale = settings.computeScaleForExtent( QgsRectangle( -500., -500., 500., 500. ) );
double widthInches = 1000 * QgsUnitTypes::fromUnitToUnitFactor( settings.mapUnits(), QgsUnitTypes::DistanceFeet ) * 12;
double testScale = widthInches * settings.outputDpi() / double( settings.outputSize().width() );
QGSCOMPARENEAR( scale, testScale, 0.001 );
}
QGSTEST_MAIN( TestQgsMapSettings ) QGSTEST_MAIN( TestQgsMapSettings )
#include "testqgsmapsettings.moc" #include "testqgsmapsettings.moc"