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 ); } } }
void QgsPointDisplacementRenderer::drawCircle( double radiusPainterUnits, QgsSymbolRenderContext &context, QPointF centerPoint, int nSymbols ) { QPainter *p = context.renderContext().painter(); if ( nSymbols < 2 || !p ) //draw circle only if multiple features { return; } //draw Circle QPen circlePen( mCircleColor ); circlePen.setWidthF( context.outputLineWidth( mCircleWidth ) ); p->setPen( circlePen ); p->drawArc( QRectF( centerPoint.x() - radiusPainterUnits, centerPoint.y() - radiusPainterUnits, 2 * radiusPainterUnits, 2 * radiusPainterUnits ), 0, 5760 ); }
void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRenderContext &symbolContext, QPointF centerPoint, int nPosition, double symbolDiagonal, QList<QPointF> &symbolPositions, QList<QPointF> &labelShifts, double &circleRadius, double &gridRadius, int &gridSize ) const { symbolPositions.clear(); labelShifts.clear(); if ( nPosition < 1 ) { return; } else if ( nPosition == 1 ) //If there is only one feature, draw it exactly at the center position { symbolPositions.append( centerPoint ); labelShifts.append( QPointF( symbolDiagonal / 2.0, -symbolDiagonal / 2.0 ) ); return; } double circleAdditionPainterUnits = symbolContext.outputLineWidth( mCircleRadiusAddition ); switch ( mPlacement ) { case Ring: { double minDiameterToFitSymbols = nPosition * symbolDiagonal / ( 2.0 * M_PI ); double radius = std::max( symbolDiagonal / 2, minDiameterToFitSymbols ) + circleAdditionPainterUnits; double fullPerimeter = 2 * M_PI; double angleStep = fullPerimeter / nPosition; for ( double currentAngle = 0.0; currentAngle < fullPerimeter; currentAngle += angleStep ) { double sinusCurrentAngle = std::sin( currentAngle ); double cosinusCurrentAngle = std::cos( currentAngle ); QPointF positionShift( radius * sinusCurrentAngle, radius * cosinusCurrentAngle ); QPointF labelShift( ( radius + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radius + symbolDiagonal / 2 ) * cosinusCurrentAngle ); symbolPositions.append( centerPoint + positionShift ); labelShifts.append( labelShift ); } circleRadius = radius; break; } case ConcentricRings: { double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2; int pointsRemaining = nPosition; int ringNumber = 1; double firstRingRadius = centerDiagonal / 2.0 + symbolDiagonal / 2.0; while ( pointsRemaining > 0 ) { double radiusCurrentRing = std::max( firstRingRadius + ( ringNumber - 1 ) * symbolDiagonal + ringNumber * circleAdditionPainterUnits, 0.0 ); int maxPointsCurrentRing = std::max( std::floor( 2 * M_PI * radiusCurrentRing / symbolDiagonal ), 1.0 ); int actualPointsCurrentRing = std::min( maxPointsCurrentRing, pointsRemaining ); double angleStep = 2 * M_PI / actualPointsCurrentRing; double currentAngle = 0.0; for ( int i = 0; i < actualPointsCurrentRing; ++i ) { double sinusCurrentAngle = std::sin( currentAngle ); double cosinusCurrentAngle = std::cos( currentAngle ); QPointF positionShift( radiusCurrentRing * sinusCurrentAngle, radiusCurrentRing * cosinusCurrentAngle ); QPointF labelShift( ( radiusCurrentRing + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radiusCurrentRing + symbolDiagonal / 2 ) * cosinusCurrentAngle ); symbolPositions.append( centerPoint + positionShift ); labelShifts.append( labelShift ); currentAngle += angleStep; } pointsRemaining -= actualPointsCurrentRing; ringNumber++; circleRadius = radiusCurrentRing; } break; } case Grid: { double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2; 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::calculateSymbolAndLabelPositions( QgsSymbolRenderContext& symbolContext, QPointF centerPoint, int nPosition, double symbolDiagonal, QList<QPointF>& symbolPositions, QList<QPointF>& labelShifts, double& circleRadius ) const { symbolPositions.clear(); labelShifts.clear(); if ( nPosition < 1 ) { return; } else if ( nPosition == 1 ) //If there is only one feature, draw it exactly at the center position { symbolPositions.append( centerPoint ); labelShifts.append( QPointF( symbolDiagonal / 2.0, -symbolDiagonal / 2.0 ) ); return; } double circleAdditionPainterUnits = symbolContext.outputLineWidth( mCircleRadiusAddition ); switch ( mPlacement ) { case Ring: { double minDiameterToFitSymbols = nPosition * symbolDiagonal / ( 2.0 * M_PI ); double radius = qMax( symbolDiagonal / 2, minDiameterToFitSymbols ) + circleAdditionPainterUnits; double fullPerimeter = 2 * M_PI; double angleStep = fullPerimeter / nPosition; for ( double currentAngle = 0.0; currentAngle < fullPerimeter; currentAngle += angleStep ) { double sinusCurrentAngle = sin( currentAngle ); double cosinusCurrentAngle = cos( currentAngle ); QPointF positionShift( radius * sinusCurrentAngle, radius * cosinusCurrentAngle ); QPointF labelShift(( radius + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radius + symbolDiagonal / 2 ) * cosinusCurrentAngle ); symbolPositions.append( centerPoint + positionShift ); labelShifts.append( labelShift ); } circleRadius = radius; break; } case ConcentricRings: { double centerDiagonal = symbolContext.renderContext().convertToPainterUnits( M_SQRT2 * mCenterSymbol->size(), mCenterSymbol->sizeUnit(), mCenterSymbol->sizeMapUnitScale() ); int pointsRemaining = nPosition; int ringNumber = 1; double firstRingRadius = centerDiagonal / 2.0 + symbolDiagonal / 2.0; while ( pointsRemaining > 0 ) { double radiusCurrentRing = qMax( firstRingRadius + ( ringNumber - 1 ) * symbolDiagonal + ringNumber * circleAdditionPainterUnits, 0.0 ); int maxPointsCurrentRing = qMax( floor( 2 * M_PI * radiusCurrentRing / symbolDiagonal ), 1.0 ); int actualPointsCurrentRing = qMin( maxPointsCurrentRing, pointsRemaining ); double angleStep = 2 * M_PI / actualPointsCurrentRing; double currentAngle = 0.0; for ( int i = 0; i < actualPointsCurrentRing; ++i ) { double sinusCurrentAngle = sin( currentAngle ); double cosinusCurrentAngle = cos( currentAngle ); QPointF positionShift( radiusCurrentRing * sinusCurrentAngle, radiusCurrentRing * cosinusCurrentAngle ); QPointF labelShift(( radiusCurrentRing + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radiusCurrentRing + symbolDiagonal / 2 ) * cosinusCurrentAngle ); symbolPositions.append( centerPoint + positionShift ); labelShifts.append( labelShift ); currentAngle += angleStep; } pointsRemaining -= actualPointsCurrentRing; ringNumber++; circleRadius = radiusCurrentRing; } break; } } }