Skip to content

Commit

Permalink
Merge pull request #5472 from nyalldawson/grid_renderer
Browse files Browse the repository at this point in the history
Grid renderer
  • Loading branch information
nyalldawson committed Oct 26, 2017
2 parents b80160a + d4e8470 commit 131b15f
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 10 deletions.
3 changes: 2 additions & 1 deletion python/core/symbology/qgspointdisplacementrenderer.sip
Expand Up @@ -23,7 +23,8 @@ class QgsPointDisplacementRenderer: QgsPointDistanceRenderer
enum Placement
{
Ring,
ConcentricRings
ConcentricRings,
Grid
};

QgsPointDisplacementRenderer( const QString &labelAttributeName = QString() );
Expand Down
1 change: 0 additions & 1 deletion src/core/auth/qgsauthcertutils.cpp
Expand Up @@ -26,7 +26,6 @@
#include "qgsapplication.h"
#include "qgsauthmanager.h"
#include "qgslogger.h"
#include "qgsapplication.h"

#ifdef Q_OS_MAC
#include <string.h>
Expand Down
90 changes: 85 additions & 5 deletions src/core/symbology/qgspointdisplacementrenderer.cpp
Expand Up @@ -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 )
{
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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 );
}
}
}

Expand Down
9 changes: 7 additions & 2 deletions src/core/symbology/qgspointdisplacementrenderer.h
Expand Up @@ -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
};

/**
Expand Down Expand Up @@ -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
1 change: 1 addition & 0 deletions src/gui/symbology/qgspointdisplacementrendererwidget.cpp
Expand Up @@ -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 )
Expand Down
2 changes: 1 addition & 1 deletion src/ui/qgspointdisplacementrendererwidgetbase.ui
Expand Up @@ -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>
Expand Down
20 changes: 20 additions & 0 deletions tests/src/python/test_qgspointdisplacementrenderer.py
Expand Up @@ -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()
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 131b15f

Please sign in to comment.