Skip to content

Commit

Permalink
Fix calculation of diagram size in map units when using scale limits
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Apr 6, 2016
1 parent ece46d1 commit 3ba3986
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 14 deletions.
14 changes: 13 additions & 1 deletion python/core/symbology-ng/qgssymbollayerv2utils.sip
Expand Up @@ -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() );

Expand Down
15 changes: 3 additions & 12 deletions src/core/qgsdiagramrendererv2.cpp
Expand Up @@ -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;
}
Expand Down
50 changes: 50 additions & 0 deletions src/core/symbology-ng/qgssymbollayerv2utils.cpp
Expand Up @@ -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 )
Expand Down
14 changes: 13 additions & 1 deletion src/core/symbology-ng/qgssymbollayerv2utils.h
Expand Up @@ -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() );

Expand Down
67 changes: 67 additions & 0 deletions tests/src/python/test_qgsmapunitscale.py
Expand Up @@ -207,6 +207,73 @@ def testConvertToPainterUnits(self):
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

Expand Down

1 comment on commit 3ba3986

@nirvn
Copy link
Contributor

@nirvn nirvn commented on 3ba3986 Apr 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Brilliant.

Please sign in to comment.