Skip to content
Permalink
Browse files

Merge pull request #5472 from nyalldawson/grid_renderer

Grid renderer
  • Loading branch information
nyalldawson committed Oct 26, 2017
2 parents b80160a + d4e8470 commit 131b15f2a72e549353a46325df2cc0db770bab59
@@ -23,7 +23,8 @@ class QgsPointDisplacementRenderer: QgsPointDistanceRenderer
enum Placement
{
Ring,
ConcentricRings
ConcentricRings,
Grid
};

QgsPointDisplacementRenderer( const QString &labelAttributeName = QString() );
@@ -26,7 +26,6 @@
#include "qgsapplication.h"
#include "qgsauthmanager.h"
#include "qgslogger.h"
#include "qgsapplication.h"

#ifdef Q_OS_MAC
#include <string.h>
@@ -75,11 +75,21 @@ void QgsPointDisplacementRenderer::drawGroup( QPointF centerPoint, QgsRenderCont
QList<QPointF> symbolPositions;
QList<QPointF> labelPositions;
double circleRadius = -1.0;
calculateSymbolAndLabelPositions( symbolContext, centerPoint, group.size(), diagonal, symbolPositions, labelPositions, circleRadius );
double gridRadius = -1.0;
int gridSize = -1;

//draw circle
if ( circleRadius > 0 )
drawCircle( circleRadius, symbolContext, centerPoint, group.size() );
calculateSymbolAndLabelPositions( symbolContext, centerPoint, group.size(), diagonal, symbolPositions, labelPositions, circleRadius, gridRadius, gridSize );

//only draw circle/grid if there's a pen present - otherwise skip drawing transparent grids
if ( mCircleColor.isValid() && mCircleColor.alpha() > 0 )
{
//draw circle
if ( circleRadius > 0 )
drawCircle( circleRadius, symbolContext, centerPoint, group.size() );
//draw grid
else
drawGrid( gridSize, symbolContext, symbolPositions, group.size() );
}

if ( group.size() > 1 )
{
@@ -221,7 +231,8 @@ void QgsPointDisplacementRenderer::setCenterSymbol( QgsMarkerSymbol *symbol )
}

void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRenderContext &symbolContext, QPointF centerPoint, int nPosition,
double symbolDiagonal, QList<QPointF> &symbolPositions, QList<QPointF> &labelShifts, double &circleRadius ) const
double symbolDiagonal, QList<QPointF> &symbolPositions, QList<QPointF> &labelShifts, double &circleRadius, double &gridRadius,
int &gridSize ) const
{
symbolPositions.clear();
labelShifts.clear();
@@ -294,6 +305,75 @@ void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRe
}
break;
}
case Grid:
{
double centerDiagonal = symbolContext.renderContext().convertToPainterUnits( M_SQRT2 * mCenterSymbol->size(),
mCenterSymbol->sizeUnit(), mCenterSymbol->sizeMapUnitScale() );
int pointsRemaining = nPosition;
gridSize = std::ceil( std::sqrt( pointsRemaining ) );
if ( pointsRemaining - std::pow( gridSize - 1, 2 ) < gridSize )
gridSize -= 1;
double originalPointRadius = ( ( centerDiagonal / 2.0 + symbolDiagonal / 2.0 ) + symbolDiagonal ) / 2;
double userPointRadius = originalPointRadius + circleAdditionPainterUnits;

int yIndex = 0;
while ( pointsRemaining > 0 )
{
for ( int xIndex = 0; xIndex < gridSize && pointsRemaining > 0; ++xIndex )
{
QPointF positionShift( userPointRadius * xIndex, userPointRadius * yIndex );
QPointF labelShift( ( userPointRadius + symbolDiagonal / 2 ) * xIndex, ( userPointRadius + symbolDiagonal / 2 ) * yIndex );
symbolPositions.append( centerPoint + positionShift );
labelShifts.append( labelShift );
pointsRemaining--;
}
yIndex++;
}

centralizeGrid( symbolPositions, userPointRadius, gridSize );
centralizeGrid( labelShifts, userPointRadius, gridSize );
gridRadius = userPointRadius;
break;
}
}
}

void QgsPointDisplacementRenderer::centralizeGrid( QList<QPointF> &pointSymbolPositions, double radius, int size ) const
{
double shiftAmount = -radius * ( size - 1.0 ) / 2.0;
QPointF centralShift( shiftAmount, shiftAmount );
for ( int i = 0; i < pointSymbolPositions.size(); ++i )
{
pointSymbolPositions[i] += centralShift;
}
}

void QgsPointDisplacementRenderer::drawGrid( int gridSizeUnits, QgsSymbolRenderContext &context,
QList<QPointF> pointSymbolPositions, int nSymbols )
{
QPainter *p = context.renderContext().painter();
if ( nSymbols < 2 || !p ) //draw grid only if multiple features
{
return;
}

QPen gridPen( mCircleColor );
gridPen.setWidthF( context.outputLineWidth( mCircleWidth ) );
p->setPen( gridPen );

for ( int i = 0; i < pointSymbolPositions.size(); ++i )
{
if ( i + 1 < pointSymbolPositions.size() && 0 != ( i + 1 ) % gridSizeUnits )
{
QLineF gridLineRow( pointSymbolPositions[i], pointSymbolPositions[i + 1] );
p->drawLine( gridLineRow );
}

if ( i + gridSizeUnits < pointSymbolPositions.size() )
{
QLineF gridLineColumn( pointSymbolPositions[i], pointSymbolPositions[i + gridSizeUnits] );
p->drawLine( gridLineColumn );
}
}
}

@@ -37,7 +37,8 @@ class CORE_EXPORT QgsPointDisplacementRenderer: public QgsPointDistanceRenderer
enum Placement
{
Ring, //!< Place points in a single ring around group
ConcentricRings //!< Place points in concentric rings around group
ConcentricRings, //!< Place points in concentric rings around group
Grid //!< Place points in a grid around group
};

/**
@@ -155,9 +156,13 @@ class CORE_EXPORT QgsPointDisplacementRenderer: public QgsPointDistanceRenderer
virtual void drawGroup( QPointF centerPoint, QgsRenderContext &context, const QgsPointDistanceRenderer::ClusteredGroup &group ) override SIP_FORCE;

//helper functions
void calculateSymbolAndLabelPositions( QgsSymbolRenderContext &symbolContext, QPointF centerPoint, int nPosition, double symbolDiagonal, QList<QPointF> &symbolPositions, QList<QPointF> &labelShifts, double &circleRadius ) const;
void calculateSymbolAndLabelPositions( QgsSymbolRenderContext &symbolContext, QPointF centerPoint, int nPosition, double symbolDiagonal, QList<QPointF> &symbolPositions, QList<QPointF> &labelShifts, double &circleRadius,
double &gridRadius, int &gridSize ) const;
void drawCircle( double radiusPainterUnits, QgsSymbolRenderContext &context, QPointF centerPoint, int nSymbols );
void drawSymbols( const ClusteredGroup &group, QgsRenderContext &context, const QList<QPointF> &symbolPositions );
void drawGrid( int gridSizeUnits, QgsSymbolRenderContext &context,
QList<QPointF> pointSymbolPositions, int nSymbols );
void centralizeGrid( QList<QPointF> &pointSymbolPositions, double radius, int size ) const;
};

#endif // QGSPOINTDISPLACEMENTRENDERER_H
@@ -79,6 +79,7 @@ QgsPointDisplacementRendererWidget::QgsPointDisplacementRendererWidget( QgsVecto

mPlacementComboBox->addItem( tr( "Ring" ), QgsPointDisplacementRenderer::Ring );
mPlacementComboBox->addItem( tr( "Concentric rings" ), QgsPointDisplacementRenderer::ConcentricRings );
mPlacementComboBox->addItem( tr( "Grid" ), QgsPointDisplacementRenderer::Grid );

//insert attributes into combo box
if ( layer )
@@ -215,7 +215,7 @@
<item row="3" column="0">
<widget class="QLabel" name="mCircleRadiusLabel">
<property name="text">
<string>Ring size adjustment</string>
<string>Size adjustment</string>
</property>
</widget>
</item>
@@ -206,6 +206,26 @@ def testRenderVariables(self):
self.layer.renderer().setCenterSymbol(old_marker)
self.assertTrue(result)

def testRenderGrid(self):
self.layer.renderer().setTolerance(10)
self.layer.renderer().setPlacement(QgsPointDisplacementRenderer.Grid)
renderchecker = QgsMultiRenderChecker()
renderchecker.setMapSettings(self.mapsettings)
renderchecker.setControlPathPrefix('displacement_renderer')
renderchecker.setControlName('expected_displacement_grid')
self.assertTrue(renderchecker.runTest('expected_displacement_grid'))

def testRenderGridAdjust(self):
self.layer.renderer().setTolerance(10)
self.layer.renderer().setCircleRadiusAddition(5)
self.layer.renderer().setPlacement(QgsPointDisplacementRenderer.Grid)
self.layer.renderer().setCircleColor(QColor())
renderchecker = QgsMultiRenderChecker()
renderchecker.setMapSettings(self.mapsettings)
renderchecker.setControlPathPrefix('displacement_renderer')
renderchecker.setControlName('expected_displacement_adjust_grid')
self.assertTrue(renderchecker.runTest('expected_displacement_adjust_grid'))


if __name__ == '__main__':
unittest.main()
Binary file not shown.
Binary file not shown.

0 comments on commit 131b15f

Please sign in to comment.
You can’t perform that action at this time.