Fix calculation of diagram size in map units when using scale limits

This commit is contained in:
Nyall Dawson 2016-04-06 22:27:07 +10:00
parent ece46d1c43
commit 3ba3986ae2
5 changed files with 146 additions and 14 deletions

View File

@ -336,10 +336,22 @@ class QgsSymbolLayerV2Utils
* @param unit units for specified size
* @param scale map unit scale
* @note added in QGIS 2.12
* @see lineWidthScaleFactor
* @see lineWidthScaleFactor()
* @see convertToMapUnits()
*/
static double convertToPainterUnits( const QgsRenderContext&c, double size, QgsSymbolV2::OutputUnit unit, const QgsMapUnitScale& scale = QgsMapUnitScale() );
/** Converts a size from the specied units to map units. The conversion respects the limits
* specified by the optional scale parameter.
* @param c render context
* @param size size to convert
* @param unit units for specified size
* @param scale map unit scale
* @note added in QGIS 2.16
* @see convertToPainterUnits()
*/
static double convertToMapUnits( const QgsRenderContext&c, double size, QgsSymbolV2::OutputUnit unit, const QgsMapUnitScale& scale = QgsMapUnitScale() );
/** Returns scale factor painter units -> pixel dimensions*/
static double pixelSizeScaleFactor( const QgsRenderContext& c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale& scale = QgsMapUnitScale() );

View File

@ -423,18 +423,9 @@ QSizeF QgsDiagramRendererV2::sizeMapUnits( const QgsFeature& feature, const QgsR
QSizeF size = diagramSize( feature, c );
if ( size.isValid() )
{
if ( s.sizeType == QgsSymbolV2::MM )
{
double pixelToMap = c.scaleFactor() * c.mapToPixel().mapUnitsPerPixel();
size.rwidth() *= pixelToMap;
size.rheight() *= pixelToMap;
}
else if ( s.sizeType == QgsSymbolV2::Pixel )
{
double pixelToMap = c.mapToPixel().mapUnitsPerPixel();
size.rwidth() *= pixelToMap;
size.rheight() *= pixelToMap;
}
double width = QgsSymbolLayerV2Utils::convertToMapUnits( c, size.width(), s.sizeType, s.sizeScale );
size.rheight() *= width / size.width();
size.setWidth( width );
}
return size;
}

View File

@ -3401,6 +3401,56 @@ double QgsSymbolLayerV2Utils::convertToPainterUnits( const QgsRenderContext &c,
return convertedSize;
}
double QgsSymbolLayerV2Utils::convertToMapUnits( const QgsRenderContext &c, double size, QgsSymbolV2::OutputUnit unit, const QgsMapUnitScale &scale )
{
double mup = c.mapToPixel().mapUnitsPerPixel();
switch ( unit )
{
case QgsSymbolV2::MapUnit:
{
// check scale
double minSizeMU = -DBL_MAX;
if ( scale.minSizeMMEnabled )
{
minSizeMU = scale.minSizeMM * c.scaleFactor() * c.rasterScaleFactor() * mup;
}
if ( !qgsDoubleNear( scale.minScale, 0.0 ) )
{
minSizeMU = qMax( minSizeMU, size * ( scale.minScale * c.rendererScale() ) );
}
size = qMax( size, minSizeMU );
double maxSizeMU = DBL_MAX;
if ( scale.maxSizeMMEnabled )
{
maxSizeMU = scale.maxSizeMM * c.scaleFactor() * c.rasterScaleFactor() * mup;
}
if ( !qgsDoubleNear( scale.maxScale, 0.0 ) )
{
maxSizeMU = qMin( maxSizeMU, size * ( scale.maxScale * c.rendererScale() ) );
}
size = qMin( size, maxSizeMU );
return size;
}
case QgsSymbolV2::MM:
{
return size * c.scaleFactor() * c.rasterScaleFactor() * mup;
}
case QgsSymbolV2::Pixel:
{
return size * mup;
}
case QgsSymbolV2::Mixed:
case QgsSymbolV2::Percentage:
//no sensible value
return 0.0;
}
return 0.0;
}
double QgsSymbolLayerV2Utils::pixelSizeScaleFactor( const QgsRenderContext& c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale& scale )
{
switch ( u )

View File

@ -388,10 +388,22 @@ class CORE_EXPORT QgsSymbolLayerV2Utils
* @param unit units for specified size
* @param scale map unit scale
* @note added in QGIS 2.12
* @see lineWidthScaleFactor
* @see lineWidthScaleFactor()
* @see convertToMapUnits()
*/
static double convertToPainterUnits( const QgsRenderContext&c, double size, QgsSymbolV2::OutputUnit unit, const QgsMapUnitScale& scale = QgsMapUnitScale() );
/** Converts a size from the specied units to map units. The conversion respects the limits
* specified by the optional scale parameter.
* @param c render context
* @param size size to convert
* @param unit units for specified size
* @param scale map unit scale
* @note added in QGIS 2.16
* @see convertToPainterUnits()
*/
static double convertToMapUnits( const QgsRenderContext&c, double size, QgsSymbolV2::OutputUnit unit, const QgsMapUnitScale& scale = QgsMapUnitScale() );
/** Returns scale factor painter units -> pixel dimensions*/
static double pixelSizeScaleFactor( const QgsRenderContext& c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale& scale = QgsMapUnitScale() );

View File

@ -207,6 +207,73 @@ class PyQgsMapUnitScale(unittest.TestCase):
size = QgsSymbolLayerV2Utils.convertToPainterUnits(r, 2, QgsSymbolV2.Pixel, c)
self.assertAlmostEqual(size, 2.0, places=5)
def testConvertToMapUnits(self):
# test QgsSymbolLayerV2Utils::convertToMapUnits() using QgsMapUnitScale
ms = QgsMapSettings()
ms.setExtent(QgsRectangle(0, 0, 100, 100))
ms.setOutputSize(QSize(100, 50))
ms.setOutputDpi(300)
r = QgsRenderContext.fromMapSettings(ms)
# renderer scale should be about 1:291937841
# start with no min/max scale
c = QgsMapUnitScale()
size = QgsSymbolLayerV2Utils.convertToMapUnits(r, 2, QgsSymbolV2.MapUnit, c)
self.assertEqual(size, 2.0)
size = QgsSymbolLayerV2Utils.convertToMapUnits(r, 2, QgsSymbolV2.MM, c)
self.assertAlmostEqual(size, 47.244094, places=5)
size = QgsSymbolLayerV2Utils.convertToMapUnits(r, 2, QgsSymbolV2.Pixel, c)
self.assertAlmostEqual(size, 4.0, places=5)
# minimum size greater than the calculated size, so size should be limited to minSizeMM
c.minSizeMM = 5
c.minSizeMMEnabled = True
size = QgsSymbolLayerV2Utils.convertToMapUnits(r, 2, QgsSymbolV2.MapUnit, c)
self.assertAlmostEqual(size, 118.1102362, places=5)
# only conversion from mapunits should be affected
size = QgsSymbolLayerV2Utils.convertToMapUnits(r, 2, QgsSymbolV2.MM, c)
self.assertAlmostEqual(size, 47.244094, places=5)
size = QgsSymbolLayerV2Utils.convertToMapUnits(r, 2, QgsSymbolV2.Pixel, c)
self.assertAlmostEqual(size, 4.0, places=5)
c.minSizeMMEnabled = False
# maximum size less than the calculated size, so size should be limited to maxSizeMM
c.maxSizeMM = 0.05
c.maxSizeMMEnabled = True
size = QgsSymbolLayerV2Utils.convertToMapUnits(r, 2, QgsSymbolV2.MapUnit, c)
self.assertAlmostEqual(size, 1.1811023622047245, places=5)
# only conversion from mapunits should be affected
size = QgsSymbolLayerV2Utils.convertToMapUnits(r, 2, QgsSymbolV2.MM, c)
self.assertAlmostEqual(size, 47.244094, places=5)
size = QgsSymbolLayerV2Utils.convertToMapUnits(r, 2, QgsSymbolV2.Pixel, c)
self.assertAlmostEqual(size, 4.0, places=5)
c.maxSizeMMEnabled = False
# test with minimum scale set
c.minScale = 1 / 150000000.0
size = QgsSymbolLayerV2Utils.convertToMapUnits(r, 2, QgsSymbolV2.MapUnit, c)
self.assertAlmostEqual(size, 15.57001821, places=5)
# only conversion from mapunits should be affected
size = QgsSymbolLayerV2Utils.convertToMapUnits(r, 2, QgsSymbolV2.MM, c)
self.assertAlmostEqual(size, 47.244094, places=5)
size = QgsSymbolLayerV2Utils.convertToMapUnits(r, 2, QgsSymbolV2.Pixel, c)
self.assertAlmostEqual(size, 4.0, places=5)
c.minScale = 0
# test with maximum scale set
c.maxScale = 1 / 1550000000.0
size = QgsSymbolLayerV2Utils.convertToMapUnits(r, 2, QgsSymbolV2.MapUnit, c)
self.assertAlmostEqual(size, 1.50677595625, places=5)
# only conversion from mapunits should be affected
size = QgsSymbolLayerV2Utils.convertToMapUnits(r, 2, QgsSymbolV2.MM, c)
self.assertAlmostEqual(size, 47.244094, places=5)
size = QgsSymbolLayerV2Utils.convertToMapUnits(r, 2, QgsSymbolV2.Pixel, c)
self.assertAlmostEqual(size, 4.0, places=5)
c.maxScale = 0
def testPixelSizeScaleFactor(self):
# test QgsSymbolLayerV2Utils::pixelSizeScaleFactor() using QgsMapUnitScale