void QgsPointDisplacementRenderer::drawGroup( QPointF centerPoint, QgsRenderContext &context, const ClusteredGroup &group )
{

  //calculate max diagonal size from all symbols in group
  double diagonal = 0;

  for ( const GroupedFeature &feature : group )
  {
    if ( QgsMarkerSymbol *symbol = feature.symbol() )
    {
      diagonal = std::max( diagonal, M_SQRT2 * symbol->size( context ) );
    }
  }

  QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderMillimeters, 1.0, false );

  QList<QPointF> symbolPositions;
  QList<QPointF> labelPositions;
  double circleRadius = -1.0;
  double gridRadius = -1.0;
  int gridSize = -1;

  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 )
  {
    //draw mid point
    QgsFeature firstFeature = group.at( 0 ).feature;
    if ( mCenterSymbol )
    {
      mCenterSymbol->renderPoint( centerPoint, &firstFeature, context, -1, false );
    }
    else
    {
      context.painter()->drawRect( QRectF( centerPoint.x() - symbolContext.outputLineWidth( 1 ), centerPoint.y() - symbolContext.outputLineWidth( 1 ), symbolContext.outputLineWidth( 2 ), symbolContext.outputLineWidth( 2 ) ) );
    }
  }

  //draw symbols on the circle
  drawSymbols( group, context, symbolPositions );
  //and also the labels
  if ( mLabelIndex >= 0 )
  {
    drawLabels( centerPoint, symbolContext, labelPositions, group );
  }
}
void QgsPointDisplacementRenderer::drawGroup( QPointF centerPoint, QgsRenderContext& context, const ClusteredGroup& group )
{

  //calculate max diagonal size from all symbols in group
  double diagonal = 0;

  Q_FOREACH ( const GroupedFeature& feature, group )
  {
    if ( QgsMarkerSymbol* symbol = feature.symbol )
    {
      diagonal = qMax( diagonal, context.convertToPainterUnits( M_SQRT2 * symbol->size(),
                       symbol->sizeUnit(), symbol->sizeMapUnitScale() ) );
    }
  }

  QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderMillimeters, 1.0, false );

  QList<QPointF> symbolPositions;
  QList<QPointF> labelPositions;
  double circleRadius = -1.0;
  calculateSymbolAndLabelPositions( symbolContext, centerPoint, group.size(), diagonal, symbolPositions, labelPositions, circleRadius );

  //draw circle
  if ( circleRadius > 0 )
    drawCircle( circleRadius, symbolContext, centerPoint, group.size() );

  if ( group.size() > 1 )
  {
    //draw mid point
    QgsFeature firstFeature = group.at( 0 ).feature;
    if ( mCenterSymbol )
    {
      mCenterSymbol->renderPoint( centerPoint, &firstFeature, context, -1, false );
    }
    else
    {
      context.painter()->drawRect( QRectF( centerPoint.x() - symbolContext.outputLineWidth( 1 ), centerPoint.y() - symbolContext.outputLineWidth( 1 ), symbolContext.outputLineWidth( 2 ), symbolContext.outputLineWidth( 2 ) ) );
    }
  }

  //draw symbols on the circle
  drawSymbols( group, context, symbolPositions );
  //and also the labels
  if ( mLabelIndex >= 0 )
  {
    drawLabels( centerPoint, symbolContext, labelPositions, group );
  }
}
bool QgsPointDisplacementRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
{
  Q_UNUSED( drawVertexMarker );
  //point position in screen coords
  QgsGeometry* geom = feature.geometry();
  QGis::WkbType geomType = geom->wkbType();
  if ( geomType != QGis::WKBPoint && geomType != QGis::WKBPoint25D )
  {
    //can only render point type
    return false;
  }
  QPointF pt;
  _getPoint( pt, context, geom->asWkb() );


  //get list of labels and symbols
  QStringList labelAttributeList;
  QList<QgsMarkerSymbolV2*> symbolList;

  if ( mDisplacementIds.contains( feature.id() ) )
  {
    //create the symbol for the whole display group if the id is the first entry in a display group
    QList<QMap<QgsFeatureId, QgsFeature> >::iterator it = mDisplacementGroups.begin();
    for ( ; it != mDisplacementGroups.end(); ++it )
    {
      //create the symbol for the whole display group if the id is the first entry in a display group
      if ( feature.id() == it->begin().key() )
      {
        QMap<QgsFeatureId, QgsFeature>::iterator attIt = it->begin();
        for ( ; attIt != it->end(); ++attIt )
        {
          if ( mDrawLabels )
          {
            labelAttributeList << getLabel( attIt.value() );
          }
          else
          {
            labelAttributeList << QString();
          }
          symbolList << dynamic_cast<QgsMarkerSymbolV2*>( firstSymbolForFeature( mRenderer, attIt.value() ) );
        }
      }
    }
  }
  else //only one feature
  {
    symbolList << dynamic_cast<QgsMarkerSymbolV2*>( firstSymbolForFeature( mRenderer, feature ) );
    if ( mDrawLabels )
    {
      labelAttributeList << getLabel( feature );
    }
    else
    {
      labelAttributeList << QString();
    }
  }

  if ( symbolList.isEmpty() && labelAttributeList.isEmpty() )
  {
    return true; //display all point symbols for one posi
  }


  //draw symbol
  double diagonal = 0;
  double currentWidthFactor; //scale symbol size to map unit and output resolution

  QList<QgsMarkerSymbolV2*>::const_iterator it = symbolList.constBegin();
  for ( ; it != symbolList.constEnd(); ++it )
  {
    if ( *it )
    {
      currentWidthFactor = QgsSymbolLayerV2Utils::lineWidthScaleFactor( context, ( *it )->outputUnit() );
      double currentDiagonal = sqrt( 2 * (( *it )->size() * ( *it )->size() ) ) * currentWidthFactor;
      if ( currentDiagonal > diagonal )
      {
        diagonal = currentDiagonal;
      }
    }
  }


  QgsSymbolV2RenderContext symbolContext( context, QgsSymbolV2::MM, 1.0, selected );
  double circleAdditionPainterUnits = symbolContext.outputLineWidth( mCircleRadiusAddition );
  double radius = qMax(( diagonal / 2 ), labelAttributeList.size() * diagonal / 2 / M_PI ) + circleAdditionPainterUnits;

  //draw Circle
  drawCircle( radius, symbolContext, pt, symbolList.size() );

  QList<QPointF> symbolPositions;
  QList<QPointF> labelPositions;
  calculateSymbolAndLabelPositions( pt, labelAttributeList.size(), radius, diagonal, symbolPositions, labelPositions );

  //draw mid point
  if ( labelAttributeList.size() > 1 )
  {
    if ( mCenterSymbol )
    {
      mCenterSymbol->renderPoint( pt, &feature, context, layer, selected );
    }
    else
    {
      context.painter()->drawRect( QRectF( pt.x() - symbolContext.outputLineWidth( 1 ), pt.y() - symbolContext.outputLineWidth( 1 ), symbolContext.outputLineWidth( 2 ), symbolContext.outputLineWidth( 2 ) ) );
    }
  }

  //draw symbols on the circle
  drawSymbols( feature, context, symbolList, symbolPositions, selected );
  //and also the labels
  drawLabels( pt, symbolContext, labelPositions, labelAttributeList );
  return true;
}
void QgsPointDisplacementRenderer::drawGroup( const DisplacementGroup& group, QgsRenderContext& context )
{
  const QgsFeature& feature = group.begin().value().first;
  bool selected = mSelectedFeatures.contains( feature.id() ); // maybe we should highlight individual features instead of the whole group?



  //get list of labels and symbols
  QStringList labelAttributeList;
  QList<QgsMarkerSymbolV2*> symbolList;

  QgsMultiPointV2* groupMultiPoint = new QgsMultiPointV2();
  for ( DisplacementGroup::const_iterator attIt = group.constBegin(); attIt != group.constEnd(); ++attIt )
  {
    labelAttributeList << ( mDrawLabels ? getLabel( attIt.value().first ) : QString() );
    symbolList << dynamic_cast<QgsMarkerSymbolV2*>( attIt.value().second );
    groupMultiPoint->addGeometry( attIt.value().first.constGeometry()->geometry()->clone() );
  }

  //calculate centroid of all points, this will be center of group
  QgsGeometry groupGeom( groupMultiPoint );
  QgsGeometry* centroid = groupGeom.centroid();
  QPointF pt;
  _getPoint( pt, context, centroid->asWkb() );
  delete centroid;

  //calculate max diagonal size from all symbols in group
  double diagonal = 0;
  Q_FOREACH ( QgsMarkerSymbolV2* symbol, symbolList )
  {
    if ( symbol )
    {
      diagonal = qMax( diagonal, QgsSymbolLayerV2Utils::convertToPainterUnits( context,
                       M_SQRT2 * symbol->size(),
                       symbol->outputUnit(), symbol->mapUnitScale() ) );
    }
  }

  QgsSymbolV2RenderContext symbolContext( context, QgsSymbolV2::MM, 1.0, selected );

  QList<QPointF> symbolPositions;
  QList<QPointF> labelPositions;
  double circleRadius = -1.0;
  calculateSymbolAndLabelPositions( symbolContext, pt, symbolList.size(), diagonal, symbolPositions, labelPositions, circleRadius );

  //draw Circle
  if ( circleRadius > 0 )
    drawCircle( circleRadius, symbolContext, pt, symbolList.size() );

  //draw mid point
  if ( labelAttributeList.size() > 1 )
  {
    if ( mCenterSymbol )
    {
      mCenterSymbol->renderPoint( pt, &feature, context, -1, selected );
    }
    else
    {
      context.painter()->drawRect( QRectF( pt.x() - symbolContext.outputLineWidth( 1 ), pt.y() - symbolContext.outputLineWidth( 1 ), symbolContext.outputLineWidth( 2 ), symbolContext.outputLineWidth( 2 ) ) );
    }
  }

  //draw symbols on the circle
  drawSymbols( feature, context, symbolList, symbolPositions, selected );
  //and also the labels
  drawLabels( pt, symbolContext, labelPositions, labelAttributeList );
}
void QgsPointDisplacementRenderer::drawGroup( const DisplacementGroup& group, QgsRenderContext& context )
{
  const QgsFeature& feature = group.begin().value().first;
  bool selected = mSelectedFeatures.contains( feature.id() ); // maybe we should highlight individual features instead of the whole group?

  QPointF pt;
  _getPoint( pt, context, feature.constGeometry()->asWkb() );

  //get list of labels and symbols
  QStringList labelAttributeList;
  QList<QgsMarkerSymbolV2*> symbolList;

  for ( DisplacementGroup::const_iterator attIt = group.constBegin(); attIt != group.constEnd(); ++attIt )
  {
    labelAttributeList << ( mDrawLabels ? getLabel( attIt.value().first ) : QString() );
    symbolList << dynamic_cast<QgsMarkerSymbolV2*>( attIt.value().second );
  }

  //draw symbol
  double diagonal = 0;
  double currentWidthFactor; //scale symbol size to map unit and output resolution

  QList<QgsMarkerSymbolV2*>::const_iterator it = symbolList.constBegin();
  for ( ; it != symbolList.constEnd(); ++it )
  {
    if ( *it )
    {
      currentWidthFactor = QgsSymbolLayerV2Utils::lineWidthScaleFactor( context, ( *it )->outputUnit(), ( *it )->mapUnitScale() );
      double currentDiagonal = sqrt( 2 * (( *it )->size() * ( *it )->size() ) ) * currentWidthFactor;
      if ( currentDiagonal > diagonal )
      {
        diagonal = currentDiagonal;
      }
    }
  }


  QgsSymbolV2RenderContext symbolContext( context, QgsSymbolV2::MM, 1.0, selected );
  double circleAdditionPainterUnits = symbolContext.outputLineWidth( mCircleRadiusAddition );
  double radius = qMax(( diagonal / 2 ), labelAttributeList.size() * diagonal / 2 / M_PI ) + circleAdditionPainterUnits;

  //draw Circle
  drawCircle( radius, symbolContext, pt, symbolList.size() );

  QList<QPointF> symbolPositions;
  QList<QPointF> labelPositions;
  calculateSymbolAndLabelPositions( pt, labelAttributeList.size(), radius, diagonal, symbolPositions, labelPositions );

  //draw mid point
  if ( labelAttributeList.size() > 1 )
  {
    if ( mCenterSymbol )
    {
      mCenterSymbol->renderPoint( pt, &feature, context, -1, selected );
    }
    else
    {
      context.painter()->drawRect( QRectF( pt.x() - symbolContext.outputLineWidth( 1 ), pt.y() - symbolContext.outputLineWidth( 1 ), symbolContext.outputLineWidth( 2 ), symbolContext.outputLineWidth( 2 ) ) );
    }
  }

  //draw symbols on the circle
  drawSymbols( feature, context, symbolList, symbolPositions, selected );
  //and also the labels
  drawLabels( pt, symbolContext, labelPositions, labelAttributeList );
}