void QgsTransformEffect::draw( QgsRenderContext &context )
{
  if ( !source() || !enabled() || !context.painter() )
    return;

  QPainter* painter = context.painter();

  //apply transformations
  painter->save();

  QTransform t = createTransform( context );
  painter->setTransform( t, true );
  drawSource( *painter );

  painter->restore();
}
Example #2
0
void QgsAnnotation::drawFrame( QgsRenderContext &context ) const
{
  if ( !mFillSymbol )
    return;

  context.painter()->setRenderHint( QPainter::Antialiasing, context.flags() & QgsRenderContext::Antialiasing );

  QPolygonF poly;
  QList<QPolygonF> rings; //empty list
  for ( int i = 0; i < 4; ++i )
  {
    QLineF currentSegment = segment( i );
    poly << currentSegment.p1();
    if ( i == mBalloonSegment && mHasFixedMapPosition )
    {
      poly << mBalloonSegmentPoint1;
      poly << QPointF( 0, 0 );
      poly << mBalloonSegmentPoint2;
    }
    poly << currentSegment.p2();
  }
  if ( poly.at( 0 ) != poly.at( poly.count() - 1 ) )
    poly << poly.at( 0 );

  mFillSymbol->startRender( context );
  mFillSymbol->renderPolygon( poly, &rings, nullptr, context );
  mFillSymbol->stopRender( context );
}
Example #3
0
void QgsEffectStackPropertiesWidget::updatePreview()
{
  QPainter painter;
  QImage previewImage( 150, 150, QImage::Format_ARGB32 );
  previewImage.fill( Qt::transparent );
  painter.begin( &previewImage );
  painter.setRenderHint( QPainter::Antialiasing );
  QgsRenderContext context = QgsSymbolLayerUtils::createRenderContext( &painter );
  if ( !mPreviewPicture )
  {
    QPicture previewPic;
    QPainter previewPicPainter;
    previewPicPainter.begin( &previewPic );
    previewPicPainter.setPen( Qt::red );
    previewPicPainter.setBrush( QColor( 255, 100, 100, 255 ) );
    previewPicPainter.drawEllipse( QPoint( 75, 75 ), 30, 30 );
    previewPicPainter.end();
    mStack->render( previewPic, context );
  }
  else
  {
    context.painter()->translate( 35, 35 );
    mStack->render( *mPreviewPicture, context );
  }
  painter.end();

  lblPreview->setPixmap( QPixmap::fromImage( previewImage ) );
  emit widgetChanged();
}
Example #4
0
void QgsAnnotation::render( QgsRenderContext &context ) const
{
  QPainter *painter = context.painter();
  if ( !painter )
  {
    return;
  }

  painter->save();
  drawFrame( context );
  if ( mHasFixedMapPosition )
  {
    drawMarkerSymbol( context );
  }
  if ( mHasFixedMapPosition )
  {
    painter->translate( mOffsetFromReferencePoint.x() + context.convertToPainterUnits( mContentsMargins.left(), QgsUnitTypes::RenderMillimeters ),
                        mOffsetFromReferencePoint.y() + context.convertToPainterUnits( mContentsMargins.top(), QgsUnitTypes::RenderMillimeters ) );
  }
  else
  {
    painter->translate( context.convertToPainterUnits( mContentsMargins.left(), QgsUnitTypes::RenderMillimeters ),
                        context.convertToPainterUnits( mContentsMargins.top(), QgsUnitTypes::RenderMillimeters ) );
  }
  QSizeF size( mFrameSize.width() - context.convertToPainterUnits( mContentsMargins.left() + mContentsMargins.right(), QgsUnitTypes::RenderMillimeters ),
               mFrameSize.height() - context.convertToPainterUnits( mContentsMargins.top() + mContentsMargins.bottom(), QgsUnitTypes::RenderMillimeters ) );

  renderAnnotation( context, size );
  painter->restore();
}
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 );
  }
}
Example #6
0
void QgsBlurEffect::drawBlurredImage( QgsRenderContext &context, QImage &image )
{
  //transparency
  QgsImageOperation::multiplyOpacity( image, 1.0 - mTransparency );

  QPainter *painter = context.painter();
  painter->save();
  painter->setCompositionMode( mBlendMode );
  painter->drawImage( imageOffset( context ), image );
  painter->restore();
}
Example #7
0
void QgsAnnotation::drawMarkerSymbol( QgsRenderContext &context ) const
{
  if ( !context.painter() )
  {
    return;
  }

  if ( mMarkerSymbol )
  {
    mMarkerSymbol->startRender( context );
    mMarkerSymbol->renderPoint( QPointF( 0, 0 ), nullptr, context );
    mMarkerSymbol->stopRender( context );
  }
}
Example #8
0
void QgsDrawSourceEffect::draw( QgsRenderContext &context )
{
  if ( !enabled() || !context.painter() )
    return;

  QPainter *painter = context.painter();

  if ( mBlendMode == QPainter::CompositionMode_SourceOver && qgsDoubleNear( mTransparency, 0.0 ) )
  {
    //just draw unmodified source
    drawSource( *painter );
  }
  else
  {
    //rasterize source and apply modifications
    QImage image = sourceAsImage( context )->copy();
    QgsImageOperation::multiplyOpacity( image, 1.0 - mTransparency );
    painter->save();
    painter->setCompositionMode( mBlendMode );
    painter->drawImage( imageOffset( context ), image );
    painter->restore();
  }
}
Example #9
0
void QgsColorEffect::draw( QgsRenderContext &context )
{
  if ( !source() || !enabled() || !context.painter() )
    return;

  QPainter* painter = context.painter();

  //rasterise source and apply modifications
  QImage image = sourceAsImage( context )->copy();

  QgsImageOperation::adjustBrightnessContrast( image, mBrightness, mContrast / 100.0 + 1 );
  if ( mGrayscaleMode != QgsImageOperation::GrayscaleOff )
  {
    QgsImageOperation::convertToGrayscale( image, static_cast< QgsImageOperation::GrayscaleMode >( mGrayscaleMode ) );
  }
  QgsImageOperation::adjustHueSaturation( image, mSaturation, mColorizeOn ? mColorizeColor : QColor(), mColorizeStrength / 100.0 );

  QgsImageOperation::multiplyOpacity( image, 1.0 - mTransparency );
  painter->save();
  painter->setCompositionMode( mBlendMode );
  painter->drawImage( imageOffset( context ), image );
  painter->restore();
}
Example #10
0
void QgsPaintEffect::begin( QgsRenderContext &context )
{
  //temporarily replace painter and direct paint operations for context to a QPicture
  mPrevPainter = context.painter();

  delete mTempPicture;
  mTempPicture = new QPicture();

  delete mEffectPainter;
  mEffectPainter = new QPainter();
  mEffectPainter->begin( mTempPicture );

  context.setPainter( mEffectPainter );
}
Example #11
0
void QgsLayoutItemHtml::render( QgsRenderContext &context, const QRectF &renderExtent, const int,
                                const QStyleOptionGraphicsItem * )
{
  if ( !mWebPage )
    return;

  QPainter *painter = context.painter();
  painter->save();
  // painter is scaled to dots, so scale back to layout units
  painter->scale( context.scaleFactor() / mHtmlUnitsToLayoutUnits, context.scaleFactor() / mHtmlUnitsToLayoutUnits );
  painter->translate( 0.0, -renderExtent.top() * mHtmlUnitsToLayoutUnits );
  mWebPage->mainFrame()->render( painter, QRegion( renderExtent.left(), renderExtent.top() * mHtmlUnitsToLayoutUnits, renderExtent.width() * mHtmlUnitsToLayoutUnits, renderExtent.height() * mHtmlUnitsToLayoutUnits ) );
  painter->restore();
}
Example #12
0
void QgsBlurEffect::draw( QgsRenderContext &context )
{
  if ( !source() || !enabled() || !context.painter() )
    return;

  switch ( mBlurMethod )
  {
    case StackBlur:
      drawStackBlur( context );
      break;
    case GaussianBlur:
      drawGaussianBlur( context );
      break;
  }
}
void QgsNumericScaleBarRenderer::draw( QgsRenderContext &context, const QgsScaleBarSettings &settings, const ScaleBarContext &scaleContext ) const
{
  if ( !context.painter() )
  {
    return;
  }

  QPainter *painter = context.painter();

  painter->save();
  if ( context.flags() & QgsRenderContext::Antialiasing )
    painter->setRenderHint( QPainter::Antialiasing, true );

  double margin = context.convertToPainterUnits( settings.boxContentSpace(), QgsUnitTypes::RenderMillimeters );
  //map scalebar alignment to Qt::AlignmentFlag type
  QgsTextRenderer::HAlignment hAlign = QgsTextRenderer::AlignLeft;
  switch ( settings.alignment() )
  {
    case QgsScaleBarSettings::AlignLeft:
      hAlign = QgsTextRenderer::AlignLeft;
      break;
    case QgsScaleBarSettings::AlignMiddle:
      hAlign = QgsTextRenderer::AlignCenter;
      break;
    case QgsScaleBarSettings::AlignRight:
      hAlign = QgsTextRenderer::AlignRight;
      break;
  }

  //text destination is item's rect, excluding the margin
  QRectF painterRect( margin, margin, context.convertToPainterUnits( scaleContext.size.width(), QgsUnitTypes::RenderMillimeters ) - 2 * margin,
                      context.convertToPainterUnits( scaleContext.size.height(), QgsUnitTypes::RenderMillimeters ) - 2 * margin );
  QgsTextRenderer::drawText( painterRect, 0, hAlign, QStringList() << scaleText( scaleContext.scale ), context, settings.textFormat() );

  painter->restore();
}
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 );
  }
}
Example #15
0
void QgsHeatmapRenderer::startRender( QgsRenderContext& context, const QgsFields& fields )
{
  Q_UNUSED( fields );
  if ( !context.painter() )
  {
    return;
  }

  // find out classification attribute index from name
  mWeightAttrNum = fields.fieldNameIndex( mWeightExpressionString );
  if ( mWeightAttrNum == -1 )
  {
    mWeightExpression.reset( new QgsExpression( mWeightExpressionString ) );
    mWeightExpression->prepare( fields );
  }

  initializeValues( context );
}
Example #16
0
void QgsLayoutItemTriangleShape::draw( QgsRenderContext &context, const QStyleOptionGraphicsItem * )
{
  QPainter *painter = context.painter();
  painter->setPen( Qt::NoPen );
  painter->setBrush( Qt::NoBrush );

  double scale = context.convertToPainterUnits( 1, QgsUnitTypes::RenderMillimeters );
  QPolygonF shapePolygon = QPolygonF() << QPointF( 0, rect().height() * scale )
                           << QPointF( rect().width() * scale, rect().height() * scale )
                           << QPointF( rect().width() / 2.0 * scale, 0 )
                           << QPointF( 0, rect().height() * scale );

  QList<QPolygonF> rings; //empty list

  symbol()->startRender( context );
  symbol()->renderPolygon( shapePolygon, &rings, nullptr, context );
  symbol()->stopRender( context );
}
void QgsInvertedPolygonRenderer::startRender( QgsRenderContext& context, const QgsFields& fields )
{
  if ( !mSubRenderer )
  {
    return;
  }

  mSubRenderer->startRender( context, fields );
  mFeaturesCategoryMap.clear();
  mFeatureDecorations.clear();
  mFields = fields;

  // We compute coordinates of the extent which will serve as exterior ring
  // for the final polygon
  // It must be computed in the destination CRS if reprojection is enabled.
  const QgsMapToPixel& mtp( context.mapToPixel() );

  // convert viewport to dest CRS
  QRect e( context.painter()->viewport() );
  // add some space to hide borders and tend to infinity
  e.adjust( -e.width()*10, -e.height()*10, e.width()*10, e.height()*10 );
  QgsPolyline exteriorRing;
  exteriorRing << mtp.toMapCoordinates( e.topLeft() );
  exteriorRing << mtp.toMapCoordinates( e.topRight() );
  exteriorRing << mtp.toMapCoordinates( e.bottomRight() );
  exteriorRing << mtp.toMapCoordinates( e.bottomLeft() );
  exteriorRing << mtp.toMapCoordinates( e.topLeft() );

  mTransform = context.coordinateTransform();
  // If reprojection is enabled, we must reproject during renderFeature
  // and act as if there is no reprojection
  // If we don't do that, there is no need to have a simple rectangular extent
  // that covers the whole screen
  // (a rectangle in the destCRS cannot be expressed as valid coordinates in the sourceCRS in general)
  if ( mTransform )
  {
    // disable projection
    context.setCoordinateTransform( 0 );
  }

  mExtentPolygon.clear();
  mExtentPolygon.append( exteriorRing );
}
Example #18
0
void QgsFormAnnotation::renderAnnotation( QgsRenderContext &context, QSizeF size ) const
{
  if ( !mDesignerWidget )
    return;

  // scale painter back to 96 dpi, so that forms look good even in layout prints
  context.painter()->save();
  const double scaleFactor = context.painter()->device()->logicalDpiX() / 96.0;
  context.painter()->scale( scaleFactor, scaleFactor );
  size /= scaleFactor;

  mDesignerWidget->setFixedSize( size.toSize() );
  context.painter()->setBrush( Qt::NoBrush );
  context.painter()->setPen( Qt::NoPen );
  mDesignerWidget->render( context.painter(), QPoint( 0, 0 ) );

  context.painter()->restore();
}
void QgsHeatmapRenderer::renderImage( QgsRenderContext& context )
{
  if ( !context.painter() || !mGradientRamp )
  {
    return;
  }

  QImage image( context.painter()->device()->width() / mRenderQuality,
                context.painter()->device()->height() / mRenderQuality,
                QImage::Format_ARGB32 );
  image.fill( Qt::transparent );

  double scaleMax = mExplicitMax > 0 ? mExplicitMax : mCalculatedMaxValue;

  int idx = 0;
  double pixVal = 0;
  QColor pixColor;
  for ( int heightIndex = 0; heightIndex < image.height(); ++heightIndex )
  {
    QRgb* scanLine = ( QRgb* )image.scanLine( heightIndex );
    for ( int widthIndex = 0; widthIndex < image.width(); ++widthIndex )
    {
      //scale result to fit in the range [0, 1]
      pixVal = mValues.at( idx ) > 0 ? qMin(( mValues.at( idx ) / scaleMax ), 1.0 ) : 0;

      //convert value to color from ramp
      pixColor = mGradientRamp->color( mInvertRamp ? 1 - pixVal : pixVal );

      scanLine[widthIndex] = pixColor.rgba();
      idx++;
    }
  }

  if ( mRenderQuality > 1 )
  {
    QImage resized = image.scaled( context.painter()->device()->width(),
                                   context.painter()->device()->height() );
    context.painter()->drawImage( 0, 0, resized );
  }
  else
  {
    context.painter()->drawImage( 0, 0, image );
  }
}
Example #20
0
void QgsLineSymbolV2::renderPolyline( const QPolygonF& points, const QgsFeature* f, QgsRenderContext& context, int layer, bool selected )
{
  //save old painter
  QPainter* renderPainter = context.painter();
  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, 0, mapUnitScale() );

  if ( layer != -1 )
  {
    if ( layer >= 0 && layer < mLayers.count() )
    {
      renderPolylineUsingLayer(( QgsLineSymbolLayerV2* ) mLayers[layer], points, symbolContext );
    }
    return;
  }

  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
  {
    renderPolylineUsingLayer(( QgsLineSymbolLayerV2* ) * it, points, symbolContext );
  }

  context.setPainter( renderPainter );
}
bool QgsInvertedPolygonRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
{
  if ( !context.painter() )
  {
    return false;
  }

  // store this feature as a feature to render with decoration if needed
  if ( selected || drawVertexMarker )
  {
    mFeatureDecorations.append( FeatureDecoration( feature, selected, drawVertexMarker, layer ) );
  }

  // Features are grouped by category of symbols (returned by symbol(s)ForFeature)
  // This way, users can have multiple inverted polygon fills for a layer,
  // for instance, with rule based renderer and different symbols
  // that have transparency.
  //
  // In order to assign a unique category to a set of symbols
  // during each rendering session (between startRender() and stopRender()),
  // we build an unique id as a QByteArray that is the concatenation
  // of each symbol's memory address.
  // The only assumption made here is that symbol(s)ForFeature will
  // always return the same address for the same symbol(s) shared amongst
  // different features.
  // This QByteArray can then be used as a key for a QMap where the list of
  // features for this category is stored
  QByteArray catId;
  if ( capabilities() & MoreSymbolsPerFeature )
  {
    QgsSymbolV2List syms( mSubRenderer->symbolsForFeature( feature, context ) );
    Q_FOREACH ( QgsSymbolV2* sym, syms )
    {
      // append the memory address
      catId.append( reinterpret_cast<const char*>( &sym ), sizeof( sym ) );
    }
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;
}
Example #23
0
void QgsPieDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
{
  QPainter* p = c.painter();
  if ( !p )
  {
    return;
  }

  //get sum of values
  QList<double> values;
  double currentVal = 0;
  double valSum = 0;
  int valCount = 0;

  QList<int>::const_iterator catIt = s.categoryIndices.constBegin();
  for ( ; catIt != s.categoryIndices.constEnd(); ++catIt )
  {
    currentVal = att[*catIt].toDouble();
    values.push_back( currentVal );
    valSum += currentVal;
    if ( currentVal ) valCount++;
  }

  //draw the slices
  double totalAngle = 0;
  double currentAngle;

  //convert from mm / map units to painter units
  QSizeF spu = sizePainterUnits( s.size, s, c );
  double w = spu.width();
  double h = spu.height();

  double baseX = position.x();
  double baseY = position.y() - h;

  mPen.setColor( s.penColor );
  setPenWidth( mPen, s, c );
  p->setPen( mPen );

  // there are some values > 0 available
  if ( valSum > 0 )
  {
    QList<double>::const_iterator valIt = values.constBegin();
    QList< QColor >::const_iterator colIt = s.categoryColors.constBegin();
    for ( ; valIt != values.constEnd(); ++valIt, ++colIt )
    {
      currentAngle =  *valIt / valSum * 360 * 16;
      mCategoryBrush.setColor( *colIt );
      p->setBrush( mCategoryBrush );
      // if only 1 value is > 0, draw a circle
      if ( valCount == 1 )
      {
        p->drawEllipse( baseX, baseY, w, h );
      }
      else
      {
        p->drawPie( baseX, baseY, w, h, totalAngle, currentAngle );
      }
      totalAngle += currentAngle;
    }
  }
  else // valSum > 0
  {
    // draw empty circle if no values are defined at all
    mCategoryBrush.setColor( Qt::transparent );
    p->setBrush( mCategoryBrush );
    p->drawEllipse( baseX, baseY, w, h );
  }
}
Example #24
0
void QgsDecorationNorthArrow::render( const QgsMapSettings &mapSettings, QgsRenderContext &context )
{

  //Large IF statement controlled by enable checkbox
  if ( enabled() )
  {
    QSize size( 64, 64 );
    QSvgRenderer svg;

    const QByteArray &svgContent = QgsApplication::svgCache()->svgContent( QStringLiteral( ":/images/north_arrows/default.svg" ), size.width(), mColor, mOutlineColor, 1.0, 1.0 );
    svg.load( svgContent );

    if ( svg.isValid() )
    {
      double centerXDouble = size.width() / 2.0;
      double centerYDouble = size.width() / 2.0;

      //save the current canvas rotation
      context.painter()->save();
      //
      //work out how to shift the image so that it rotates
      //           properly about its center
      //(x cos a + y sin a - x, -x sin a + y cos a - y)
      //

      // could move this call to somewhere else so that it is only
      // called when the projection or map extent changes
      if ( mAutomatic )
      {
        mRotationInt = QgsBearingUtils:: bearingTrueNorth( mapSettings.destinationCrs(), context.extent().center() );
        mRotationInt += mapSettings.rotation();
      }

      double myRadiansDouble = mRotationInt * M_PI / 180.0;
      int xShift = static_cast<int>( (
                                       ( centerXDouble * cos( myRadiansDouble ) ) +
                                       ( centerYDouble * sin( myRadiansDouble ) )
                                     ) - centerXDouble );
      int yShift = static_cast<int>( (
                                       ( -centerXDouble * sin( myRadiansDouble ) ) +
                                       ( centerYDouble * cos( myRadiansDouble ) )
                                     ) - centerYDouble );

      // need width/height of paint device
      int myHeight = context.painter()->device()->height();
      int myWidth = context.painter()->device()->width();

      //QgsDebugMsg("Rendering north arrow at " + mPlacementLabels.at(mPlacementIndex));

      // Set  margin according to selected units
      int myXOffset = 0;
      int myYOffset = 0;
      switch ( mMarginUnit )
      {
        case QgsUnitTypes::RenderMillimeters:
        {
          int myPixelsInchX = context.painter()->device()->logicalDpiX();
          int myPixelsInchY = context.painter()->device()->logicalDpiY();
          myXOffset = myPixelsInchX * INCHES_TO_MM * mMarginHorizontal;
          myYOffset = myPixelsInchY * INCHES_TO_MM * mMarginVertical;
          break;
        }

        case QgsUnitTypes::RenderPixels:
          myXOffset = mMarginHorizontal - 5; // Minus 5 to shift tight into corner
          myYOffset = mMarginVertical - 5;
          break;

        case QgsUnitTypes::RenderPercentage:
          myXOffset = ( ( myWidth - size.width() ) / 100. ) * mMarginHorizontal;
          myYOffset = ( ( myHeight - size.width() ) / 100. ) * mMarginVertical;
          break;

        default:  // Use default of top left
          break;
      }
      //Determine placement of label from form combo box
      switch ( mPlacement )
      {
        case BottomLeft:
          context.painter()->translate( myXOffset, myHeight - myYOffset - size.width() );
          break;
        case TopLeft:
          context.painter()->translate( myXOffset, myYOffset );
          break;
        case TopRight:
          context.painter()->translate( myWidth - myXOffset - size.width(), myYOffset );
          break;
        case BottomRight:
          context.painter()->translate( myWidth - myXOffset - size.width(),
                                        myHeight - myYOffset - size.width() );
          break;
        default:
        {
          //QgsDebugMsg("Unable to determine where to put north arrow so defaulting to top left");
        }
      }

      //rotate the canvas by the north arrow rotation amount
      context.painter()->rotate( mRotationInt );
      //Now we can actually do the drawing, and draw a smooth north arrow even when rotated

      context.painter()->translate( xShift, yShift );
      svg.render( context.painter(), QRectF( 0, 0, size.width(), size.height() ) );

      //unrotate the canvas again
      context.painter()->restore();
    }
    else
    {
      QFont myQFont( QStringLiteral( "time" ), 12, QFont::Bold );
      context.painter()->setFont( myQFont );
      context.painter()->setPen( Qt::black );
      context.painter()->drawText( 10, 20, tr( "North arrow pixmap not found" ) );
    }
  }

}
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 );
}
bool QgsHeatmapRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
{
  Q_UNUSED( layer );
  Q_UNUSED( selected );
  Q_UNUSED( drawVertexMarker );

  if ( !context.painter() )
  {
    return false;
  }

  if ( !feature.constGeometry() || feature.constGeometry()->type() != QGis::Point )
  {
    //can only render point type
    return false;
  }

  double weight = 1.0;
  if ( !mWeightExpressionString.isEmpty() )
  {
    QVariant value;
    if ( mWeightAttrNum == -1 )
    {
      Q_ASSERT( mWeightExpression.data() );
      value = mWeightExpression->evaluate( &feature );
    }
    else
    {
      QgsAttributes attrs = feature.attributes();
      value = attrs.value( mWeightAttrNum );
    }
    bool ok = false;
    double evalWeight = value.toDouble( &ok );
    if ( ok )
    {
      weight = evalWeight;
    }
  }

  int width = context.painter()->device()->width() / mRenderQuality;
  int height = context.painter()->device()->height() / mRenderQuality;

  //transform geometry if required
  QgsGeometry* transformedGeom = 0;
  const QgsCoordinateTransform* xform = context.coordinateTransform();
  if ( xform )
  {
    transformedGeom = new QgsGeometry( *feature.constGeometry() );
    transformedGeom->transform( *xform );
  }

  //convert point to multipoint
  QgsMultiPoint multiPoint = convertToMultipoint( transformedGeom ? transformedGeom : feature.constGeometry() );

  delete transformedGeom;
  transformedGeom = 0;

  //loop through all points in multipoint
  for ( QgsMultiPoint::const_iterator pointIt = multiPoint.constBegin(); pointIt != multiPoint.constEnd(); ++pointIt )
  {
    QgsPoint pixel = context.mapToPixel().transform( *pointIt );
    int pointX = pixel.x() / mRenderQuality;
    int pointY = pixel.y() / mRenderQuality;
    for ( int x = qMax( pointX - mRadiusPixels, 0 ); x < qMin( pointX + mRadiusPixels, width ); ++x )
    {
      for ( int y = qMax( pointY - mRadiusPixels, 0 ); y < qMin( pointY + mRadiusPixels, height ); ++y )
      {
        int index = y * width + x;
        if ( index >= mValues.count( ) )
        {
          continue;
        }
        double distanceSquared = pow( pointX - x, 2.0 ) + pow( pointY - y, 2.0 );
        if ( distanceSquared > mRadiusSquared )
        {
          continue;
        }

        double score = weight * quarticKernel( sqrt( distanceSquared ), mRadiusPixels );
        double value = mValues[ index ] + score;
        if ( value > mCalculatedMaxValue )
        {
          mCalculatedMaxValue = value;
        }
        mValues[ index ] = value;
      }
    }
  }

  mFeaturesRendered++;
#if 0
  //TODO - enable progressive rendering
  if ( mFeaturesRendered % 200  == 0 )
  {
    renderImage( context );
  }
#endif
  return true;
}
Example #27
0
void QgsHistogramDiagram::renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, QPointF position )
{
  QPainter* p = c.painter();
  if ( !p )
  {
    return;
  }

  QList<double> values;
  double maxValue = 0;

  QgsExpressionContext expressionContext = c.expressionContext();
  expressionContext.setFeature( feature );
  if ( !feature.fields().isEmpty() )
    expressionContext.setFields( feature.fields() );

  Q_FOREACH ( const QString& cat, s.categoryAttributes )
  {
    QgsExpression* expression = getExpression( cat, expressionContext );
    double currentVal = expression->evaluate( &expressionContext ).toDouble();
    values.push_back( currentVal );
    maxValue = qMax( currentVal, maxValue );
  }

  double scaledMaxVal = sizePainterUnits( maxValue * mScaleFactor, s, c );

  double currentOffset = 0;
  double scaledWidth = sizePainterUnits( s.barWidth, s, c );

  double baseX = position.x();
  double baseY = position.y();

  mPen.setColor( s.penColor );
  setPenWidth( mPen, s, c );
  p->setPen( mPen );

  QList<double>::const_iterator valIt = values.constBegin();
  QList< QColor >::const_iterator colIt = s.categoryColors.constBegin();
  for ( ; valIt != values.constEnd(); ++valIt, ++colIt )
  {
    double length = sizePainterUnits( *valIt * mScaleFactor, s, c );

    mCategoryBrush.setColor( *colIt );
    p->setBrush( mCategoryBrush );

    switch ( s.diagramOrientation )
    {
      case QgsDiagramSettings::Up:
        p->drawRect( baseX + currentOffset, baseY, scaledWidth, length * -1 );
        break;

      case QgsDiagramSettings::Down:
        p->drawRect( baseX + currentOffset, baseY - scaledMaxVal, scaledWidth, length );
        break;

      case QgsDiagramSettings::Right:
        p->drawRect( baseX, baseY - currentOffset, length, scaledWidth * -1 );
        break;

      case QgsDiagramSettings::Left:
        p->drawRect( baseX + scaledMaxVal, baseY - currentOffset, 0 - length, scaledWidth * -1 );
        break;
    }

    currentOffset += scaledWidth;
  }
}
void QgsDecorationNorthArrow::render( const QgsMapSettings &mapSettings, QgsRenderContext &context )
{
  if ( !enabled() )
    return;

  double maxLength = mSize * mapSettings.outputDpi() / 25.4;
  QSvgRenderer svg;

  const QByteArray &svgContent = QgsApplication::svgCache()->svgContent( svgPath(), maxLength, mColor, mOutlineColor, 1.0, 1.0 );
  svg.load( svgContent );

  if ( svg.isValid() )
  {
    QSize size( maxLength, maxLength );
    QRectF viewBox = svg.viewBoxF();
    if ( viewBox.height() > viewBox.width() )
    {
      size.setWidth( maxLength * viewBox.width() / viewBox.height() );
    }
    else
    {
      size.setHeight( maxLength * viewBox.height() / viewBox.width() );
    }

    double centerXDouble = size.width() / 2.0;
    double centerYDouble = size.height() / 2.0;

    //save the current canvas rotation
    context.painter()->save();
    //
    //work out how to shift the image so that it rotates
    //           properly about its center
    //(x cos a + y sin a - x, -x sin a + y cos a - y)
    //
    // could move this call to somewhere else so that it is only
    // called when the projection or map extent changes
    if ( mAutomatic )
    {
      try
      {
        mRotationInt = QgsBearingUtils:: bearingTrueNorth( mapSettings.destinationCrs(), mapSettings.transformContext(), context.extent().center() );
      }
      catch ( QgsException & )
      {
        mRotationInt = 0.0;
      }
      mRotationInt += mapSettings.rotation();
    }

    double radiansDouble = mRotationInt * M_PI / 180.0;
    int xShift = static_cast<int>( (
                                     ( centerXDouble * std::cos( radiansDouble ) ) +
                                     ( centerYDouble * std::sin( radiansDouble ) )
                                   ) - centerXDouble );
    int yShift = static_cast<int>( (
                                     ( -centerXDouble * std::sin( radiansDouble ) ) +
                                     ( centerYDouble * std::cos( radiansDouble ) )
                                   ) - centerYDouble );
    // need width/height of paint device
    int deviceHeight = context.painter()->device()->height();
    int deviceWidth = context.painter()->device()->width();

    // Set  margin according to selected units
    int xOffset = 0;
    int yOffset = 0;
    switch ( mMarginUnit )
    {
      case QgsUnitTypes::RenderMillimeters:
      {
        int pixelsInchX = context.painter()->device()->logicalDpiX();
        int pixelsInchY = context.painter()->device()->logicalDpiY();
        xOffset = pixelsInchX * INCHES_TO_MM * mMarginHorizontal;
        yOffset = pixelsInchY * INCHES_TO_MM * mMarginVertical;
        break;
      }

      case QgsUnitTypes::RenderPixels:
        xOffset = mMarginHorizontal - 5; // Minus 5 to shift tight into corner
        yOffset = mMarginVertical - 5;
        break;

      case QgsUnitTypes::RenderPercentage:
        xOffset = ( ( deviceWidth - size.width() ) / 100. ) * mMarginHorizontal;
        yOffset = ( ( deviceHeight - size.width() ) / 100. ) * mMarginVertical;
        break;
      case QgsUnitTypes::RenderMapUnits:
      case QgsUnitTypes::RenderPoints:
      case QgsUnitTypes::RenderInches:
      case QgsUnitTypes::RenderUnknownUnit:
      case QgsUnitTypes::RenderMetersInMapUnits:
        break;
    }
    //Determine placement of label from form combo box
    switch ( mPlacement )
    {
      case BottomLeft:
        context.painter()->translate( xOffset, deviceHeight - yOffset - maxLength + ( maxLength - size.height() ) / 2 );
        break;
      case TopLeft:
        context.painter()->translate( xOffset, yOffset );
        break;
      case TopRight:
        context.painter()->translate( deviceWidth - xOffset - maxLength + ( maxLength - size.width() ) / 2, yOffset );
        break;
      case BottomRight:
        context.painter()->translate( deviceWidth - xOffset - maxLength + ( maxLength - size.width() ) / 2,
                                      deviceHeight - yOffset - maxLength + ( maxLength - size.height() ) / 2 );
        break;
    }

    //rotate the canvas by the north arrow rotation amount
    context.painter()->rotate( mRotationInt );
    //Now we can actually do the drawing, and draw a smooth north arrow even when rotated
    context.painter()->translate( xShift, yShift );
    svg.render( context.painter(), QRectF( 0, 0, size.width(), size.height() ) );

    //unrotate the canvas again
    context.painter()->restore();
  }
}
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 );
}
Example #30
0
void QgsTextDiagram::renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, QPointF position )
{
  QPainter* p = c.painter();
  if ( !p )
  {
    return;
  }

  //convert from mm / map units to painter units
  QSizeF spu = sizePainterUnits( s.size, s, c );
  double w = spu.width();
  double h = spu.height();

  double baseX = position.x();
  double baseY = position.y() - h;

  QVector<QPointF> textPositions; //midpoints for text placement
  int nCategories = s.categoryAttributes.size();
  for ( int i = 0; i < nCategories; ++i )
  {
    if ( mOrientation == Horizontal )
    {
      textPositions.push_back( QPointF( baseX + ( w / nCategories ) * i + w / nCategories / 2.0, baseY + h / 2.0 ) );
    }
    else //vertical
    {
      textPositions.push_back( QPointF( baseX + w / 2.0, baseY + h / nCategories * i + w / nCategories / 2.0 ) );
    }
  }

  mPen.setColor( s.penColor );
  setPenWidth( mPen, s, c );
  p->setPen( mPen );
  mBrush.setColor( s.backgroundColor );
  p->setBrush( mBrush );

  //draw shapes and separator lines first
  if ( mShape == Circle )
  {
    p->drawEllipse( baseX, baseY, w, h );

    //draw separator lines
    QList<QPointF> intersect; //intersections between shape and separation lines
    QPointF center( baseX + w / 2.0, baseY + h / 2.0 );
    double r1 = w / 2.0;
    double r2 = h / 2.0;

    for ( int i = 1; i < nCategories; ++i )
    {
      if ( mOrientation == Horizontal )
      {
        lineEllipseIntersection( QPointF( baseX + w / nCategories * i, baseY ), QPointF( baseX + w / nCategories * i, baseY + h ), center, r1, r2, intersect );
      }
      else //vertical
      {
        lineEllipseIntersection( QPointF( baseX, baseY + h / nCategories * i ), QPointF( baseX + w, baseY + h / nCategories * i ), center, r1, r2, intersect );
      }
      if ( intersect.size() > 1 )
      {
        p->drawLine( intersect.at( 0 ), intersect.at( 1 ) );
      }
    }
  }
  else if ( mShape == Rectangle )
  {
    p->drawRect( QRectF( baseX, baseY, w, h ) );
    for ( int i = 1; i < nCategories; ++i )
    {
      if ( mOrientation == Horizontal )
      {
        p->drawLine( QPointF( baseX + w / nCategories * i, baseY ), QPointF( baseX + w / nCategories * i, baseY + h ) );
      }
      else
      {
        p->drawLine( QPointF( baseX, baseY + h / nCategories * i ), QPointF( baseX + w, baseY + h / nCategories * i ) );
      }
    }
  }
  else //triangle
  {
    QPolygonF triangle;
    triangle << QPointF( baseX, baseY + h ) << QPointF( baseX + w, baseY + h ) << QPointF( baseX + w / 2.0, baseY );
    p->drawPolygon( triangle );

    QLineF triangleEdgeLeft( baseX + w / 2.0, baseY, baseX, baseY + h );
    QLineF triangleEdgeRight( baseX + w, baseY + h, baseX + w / 2.0, baseY );
    QPointF intersectionPoint1, intersectionPoint2;

    for ( int i = 1; i < nCategories; ++i )
    {
      if ( mOrientation == Horizontal )
      {
        QLineF verticalLine( baseX + w / nCategories * i, baseY + h, baseX + w / nCategories * i, baseY );
        if ( baseX + w / nCategories * i < baseX + w / 2.0 )
        {
          verticalLine.intersect( triangleEdgeLeft, &intersectionPoint1 );
        }
        else
        {
          verticalLine.intersect( triangleEdgeRight, &intersectionPoint1 );
        }
        p->drawLine( QPointF( baseX + w / nCategories * i, baseY + h ), intersectionPoint1 );
      }
      else //vertical
      {
        QLineF horizontalLine( baseX, baseY + h / nCategories * i, baseX + w, baseY + h / nCategories * i );
        horizontalLine.intersect( triangleEdgeLeft, &intersectionPoint1 );
        horizontalLine.intersect( triangleEdgeRight, &intersectionPoint2 );
        p->drawLine( intersectionPoint1, intersectionPoint2 );
      }
    }
  }

  //draw text
  QFont sFont = scaledFont( s, c );
  QFontMetricsF fontMetrics( sFont );
  p->setFont( sFont );

  QgsExpressionContext expressionContext = c.expressionContext();
  expressionContext.setFeature( feature );
  if ( feature.fields() )
    expressionContext.setFields( *feature.fields() );

  for ( int i = 0; i < textPositions.size(); ++i )
  {
    QgsExpression* expression = getExpression( s.categoryAttributes.at( i ), expressionContext );
    QString val = expression->evaluate( &expressionContext ).toString();

    //find out dimesions
    double textWidth = fontMetrics.width( val );
    double textHeight = fontMetrics.height();

    mPen.setColor( s.categoryColors.at( i ) );
    p->setPen( mPen );
    QPointF position = textPositions.at( i );

    // Calculate vertical placement
    double xOffset = 0;

    switch ( s.labelPlacementMethod )
    {
      case QgsDiagramSettings::Height:
        xOffset = textHeight / 2.0;
        break;

      case QgsDiagramSettings::XHeight:
        xOffset = fontMetrics.xHeight();
        break;
    }
    p->drawText( QPointF( position.x() - textWidth / 2.0, position.y() + xOffset ), val );
  }
}