void QgsEllipseSymbolLayerV2::renderPoint( QPointF point, QgsSymbolV2RenderContext& context )
{
  bool ok;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH ) )
  {
    context.setOriginalValueVariable( mOutlineWidth );
    double width = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
    width = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), width, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
    mPen.setWidthF( width );
  }
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_STYLE ) )
  {
    context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodePenStyle( mOutlineStyle ) );
    QString styleString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_STYLE, context, QVariant(), &ok ).toString();
    if ( ok )
    {
      Qt::PenStyle style = QgsSymbolLayerV2Utils::decodePenStyle( styleString );
      mPen.setStyle( style );
    }
  }
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_JOIN_STYLE ) )
  {
    context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodePenJoinStyle( mPenJoinStyle ) );
    QString style = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_JOIN_STYLE, context, QVariant(), &ok ).toString();
    if ( ok )
    {
      mPen.setJoinStyle( QgsSymbolLayerV2Utils::decodePenJoinStyle( style ) );
    }
  }
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_FILL_COLOR ) )
  {
    context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodeColor( mColor ) );
    QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_FILL_COLOR, context, QVariant(), &ok ).toString();
    if ( ok )
      mBrush.setColor( QgsSymbolLayerV2Utils::decodeColor( colorString ) );
  }
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_COLOR ) )
  {
    context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodeColor( mOutlineColor ) );
    QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_COLOR, context, QVariant(), &ok ).toString();
    if ( ok )
      mPen.setColor( QgsSymbolLayerV2Utils::decodeColor( colorString ) );
  }
  double scaledWidth = mSymbolWidth;
  double scaledHeight = mSymbolHeight;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH ) || hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT ) || hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_SYMBOL_NAME ) )
  {
    QString symbolName =  mSymbolName;
    if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_SYMBOL_NAME ) )
    {
      context.setOriginalValueVariable( mSymbolName );
      symbolName = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SYMBOL_NAME, context, mSymbolName ).toString();
    }
    preparePath( symbolName, context, &scaledWidth, &scaledHeight, context.feature() );
  }

  //offset and rotation
  bool hasDataDefinedRotation = false;
  QPointF offset;
  double angle = 0;
  calculateOffsetAndRotation( context, scaledWidth, scaledHeight, hasDataDefinedRotation, offset, angle );

  QPainter* p = context.renderContext().painter();
  if ( !p )
  {
    return;
  }

  QMatrix transform;
  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
  if ( !qgsDoubleNear( angle, 0.0 ) )
  {
    transform.rotate( angle );
  }

  p->setPen( mPen );
  p->setBrush( mBrush );
  p->drawPath( transform.map( mPainterPath ) );
}
QRectF QgsEllipseSymbolLayerV2::bounds( QPointF point, QgsSymbolV2RenderContext& context )
{
  QSizeF size = calculateSize( context );

  bool hasDataDefinedRotation = false;
  QPointF offset;
  double angle = 0;
  calculateOffsetAndRotation( context, size.width(), size.height(), hasDataDefinedRotation, offset, angle );

  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();

  QMatrix transform;

  // move to the desired position
  transform.translate( point.x() + offset.x(), point.y() + offset.y() );

  if ( !qgsDoubleNear( angle, 0.0 ) )
    transform.rotate( angle );

  double penWidth = 0.0;
  bool ok = true;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH ) )
  {
    context.setOriginalValueVariable( mOutlineWidth );
    double outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, QVariant(), &ok ).toDouble();
    if ( ok )
    {
      penWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
    }
  }
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_STYLE ) )
  {
    context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodePenStyle( mOutlineStyle ) );
    QString outlineStyle = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_STYLE, context, QVariant(), &ok ).toString();
    if ( ok && outlineStyle == "no" )
    {
      penWidth = 0.0;
    }
  }

  //antialiasing
  penWidth += pixelSize;

  QRectF symbolBounds = transform.mapRect( QRectF( -size.width() / 2.0,
                        -size.height() / 2.0,
                        size.width(),
                        size.height() ) );

  //extend bounds by pen width / 2.0
  symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
                       penWidth / 2.0, penWidth / 2.0 );

  return symbolBounds;
}
Beispiel #3
0
void QgsArrowSymbolLayer::_resolveDataDefined( QgsSymbolV2RenderContext& context )
{
  if ( !hasDataDefinedProperties() )
    return; // shortcut if case there is no data defined properties at all

  bool ok;
  if ( hasDataDefinedProperty( "arrow_width" ) )
  {
    context.setOriginalValueVariable( arrowWidth() );
    double w = evaluateDataDefinedProperty( "arrow_width", context, QVariant(), &ok ).toDouble();
    if ( ok )
    {
      mScaledArrowWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), w, arrowWidthUnit(), arrowWidthUnitScale() );
    }
  }
  if ( hasDataDefinedProperty( "arrow_start_width" ) )
  {
    context.setOriginalValueVariable( arrowStartWidth() );
    double w = evaluateDataDefinedProperty( "arrow_start_width", context, QVariant(), &ok ).toDouble();
    if ( ok )
    {
      mScaledArrowStartWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), w, arrowStartWidthUnit(), arrowStartWidthUnitScale() );
    }
  }
  if ( hasDataDefinedProperty( "head_size" ) )
  {
    context.setOriginalValueVariable( headSize() );
    double w = evaluateDataDefinedProperty( "head_size", context, QVariant(), &ok ).toDouble();
    if ( ok )
    {
      mScaledHeadSize = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), w, headSizeUnit(), headSizeUnitScale() );
    }
  }
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET ) )
  {
    context.setOriginalValueVariable( offset() );
    double w = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET, context, QVariant(), &ok ).toDouble();
    if ( ok )
    {
      mScaledOffset = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), w, offsetUnit(), offsetMapUnitScale() );
    }
  }

  if ( hasDataDefinedProperty( "head_type" ) )
  {
    context.setOriginalValueVariable( headType() );
    int h = evaluateDataDefinedProperty( "head_type", context, QVariant(), &ok ).toInt();
    if ( ok )
    {
      mComputedHeadType = static_cast<HeadType>( h );
    }
  }
}
QSizeF QgsEllipseSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context, double* scaledWidth, double* scaledHeight )
{
  double width = 0;

  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH ) ) //1. priority: data defined setting on symbol layer le
  {
    context.setOriginalValueVariable( mSymbolWidth );
    width = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, context, mSymbolWidth ).toDouble();
  }
  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
  {
    width = mSize;
  }
  else //3. priority: global width setting
  {
    width = mSymbolWidth;
  }
  if ( scaledWidth )
  {
    *scaledWidth = width;
  }
  width = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), width, mSymbolWidthUnit, mSymbolHeightMapUnitScale );

  double height = 0;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT ) ) //1. priority: data defined setting on symbol layer level
  {
    context.setOriginalValueVariable( mSymbolHeight );
    height = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT, context, mSymbolHeight ).toDouble();
  }
  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
  {
    height = mSize;
  }
  else //3. priority: global height setting
  {
    height = mSymbolHeight;
  }
  if ( scaledHeight )
  {
    *scaledHeight = height;
  }
  height = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), height, mSymbolHeightUnit, mSymbolHeightMapUnitScale );
  return QSizeF( width, height );
}
Beispiel #5
0
void QgsMarkerSymbolLayerV2::markerOffset( QgsSymbolV2RenderContext& context, double width, double height,
    QgsUnitTypes::RenderUnit widthUnit, QgsUnitTypes::RenderUnit heightUnit,
    double& offsetX, double& offsetY, const QgsMapUnitScale& widthMapUnitScale, const QgsMapUnitScale& heightMapUnitScale ) const
{
  offsetX = mOffset.x();
  offsetY = mOffset.y();

  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET ) )
  {
    context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodePoint( mOffset ) );
    QPointF offset = QgsSymbolLayerV2Utils::decodePoint( evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET, context ).toString() );
    offsetX = offset.x();
    offsetY = offset.y();
  }

  offsetX = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), offsetX, mOffsetUnit, mOffsetMapUnitScale );
  offsetY = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), offsetY, mOffsetUnit, mOffsetMapUnitScale );

  HorizontalAnchorPoint horizontalAnchorPoint = mHorizontalAnchorPoint;
  VerticalAnchorPoint verticalAnchorPoint = mVerticalAnchorPoint;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_HORIZONTAL_ANCHOR_POINT ) )
  {
    horizontalAnchorPoint = decodeHorizontalAnchorPoint( evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_HORIZONTAL_ANCHOR_POINT , context ).toString() );
  }
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_VERTICAL_ANCHOR_POINT ) )
  {
    verticalAnchorPoint = decodeVerticalAnchorPoint( evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_VERTICAL_ANCHOR_POINT, context ).toString() );
  }

  //correct horizontal position according to anchor point
  if ( horizontalAnchorPoint == HCenter && verticalAnchorPoint == VCenter )
  {
    return;
  }

  double anchorPointCorrectionX = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), width, widthUnit, widthMapUnitScale ) / 2.0;
  double anchorPointCorrectionY = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), height, heightUnit, heightMapUnitScale ) / 2.0;
  if ( horizontalAnchorPoint == Left )
  {
    offsetX += anchorPointCorrectionX;
  }
  else if ( horizontalAnchorPoint == Right )
  {
    offsetX -= anchorPointCorrectionX;
  }

  //correct vertical position according to anchor point
  if ( verticalAnchorPoint == Top )
  {
    offsetY += anchorPointCorrectionY;
  }
  else if ( verticalAnchorPoint == Bottom )
  {
    offsetY -= anchorPointCorrectionY;
  }
}
double QgsSimpleLineSymbolLayerV2::dxfOffset( const QgsDxfExport& e, QgsSymbolV2RenderContext &context ) const
{
  Q_UNUSED( e );
  double offset = mOffset;

  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET ) )
  {
    context.setOriginalValueVariable( mOffset );
    offset = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET, context, mOffset ).toDouble();
  }
  return offset;
}
QColor QgsSimpleLineSymbolLayerV2::dxfColor( QgsSymbolV2RenderContext& context ) const
{
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_COLOR ) )
  {
    bool ok;
    context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodeColor( mColor ) );
    QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_COLOR, context, QVariant(), &ok ).toString();
    if ( ok )
      return ( QgsSymbolLayerV2Utils::decodeColor( colorString ) );
  }
  return mColor;
}
double QgsSimpleLineSymbolLayerV2::dxfWidth( const QgsDxfExport& e, QgsSymbolV2RenderContext& context ) const
{
  double width = mWidth;

  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH ) )
  {
    context.setOriginalValueVariable( mWidth );
    width = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, context, mWidth ).toDouble() * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), widthUnit(), e.mapUnits() );
  }
  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
  {
    width = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mWidth, mWidthUnit, mWidthMapUnitScale );
  }

  return width * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), widthUnit(), e.mapUnits() );
}
void QgsEllipseSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context,
    double scaledWidth,
    double scaledHeight,
    bool& hasDataDefinedRotation,
    QPointF& offset,
    double& angle ) const
{
  double offsetX = 0;
  double offsetY = 0;
  markerOffset( context, scaledWidth, scaledHeight, mSymbolWidthUnit, mSymbolHeightUnit, offsetX, offsetY, mSymbolWidthMapUnitScale, mSymbolHeightMapUnitScale );
  offset = QPointF( offsetX, offsetY );

//priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
  bool ok = true;
  angle = mAngle + mLineAngle;
  bool usingDataDefinedRotation = false;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_ROTATION ) )
  {
    context.setOriginalValueVariable( angle );
    angle = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_ROTATION, context, mAngle, &ok ).toDouble() + mLineAngle;
    usingDataDefinedRotation = ok;
  }

  hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || usingDataDefinedRotation;
  if ( hasDataDefinedRotation )
  {
    // For non-point markers, "dataDefinedRotation" means following the
    // shape (shape-data defined). For them, "field-data defined" does
    // not work at all. TODO: if "field-data defined" ever gets implemented
    // we'll need a way to distinguish here between the two, possibly
    // using another flag in renderHints()
    const QgsFeature* f = context.feature();
    if ( f )
    {
      const QgsGeometry *g = f->constGeometry();
      if ( g && g->type() == QGis::Point )
      {
        const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
        angle += m2p.mapRotation();
      }
    }
  }

  if ( angle )
    offset = _rotatedOffset( offset, angle );
}
void QgsMarkerLineSymbolLayerV2::renderPolylineVertex( const QPolygonF& points, QgsSymbolV2RenderContext& context, Placement placement )
{
  if ( points.isEmpty() )
    return;

  QgsRenderContext& rc = context.renderContext();

  double origAngle = mMarker->angle();
  int i, maxCount;
  bool isRing = false;

  double offsetAlongLine = mOffsetAlongLine;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET_ALONG_LINE ) )
  {
    context.setOriginalValueVariable( mOffsetAlongLine );
    offsetAlongLine = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET_ALONG_LINE, context, mOffsetAlongLine ).toDouble();
  }
  if ( offsetAlongLine != 0 )
  {
    //scale offset along line
    offsetAlongLine = QgsSymbolLayerV2Utils::convertToPainterUnits( rc, offsetAlongLine, mOffsetAlongLineUnit, mOffsetAlongLineMapUnitScale );
  }

  if ( offsetAlongLine == 0 && context.renderContext().geometry()
       && context.renderContext().geometry()->hasCurvedSegments() && ( placement == Vertex || placement == CurvePoint ) )
  {
    const QgsCoordinateTransform* ct = context.renderContext().coordinateTransform();
    const QgsMapToPixel& mtp = context.renderContext().mapToPixel();

    QgsVertexId vId;
    QgsPointV2 vPoint;
    double x, y, z;
    QPointF mapPoint;
    while ( context.renderContext().geometry()->nextVertex( vId, vPoint ) )
    {
      if (( placement == Vertex && vId.type == QgsVertexId::SegmentVertex )
          || ( placement == CurvePoint && vId.type == QgsVertexId::CurveVertex ) )
      {
        //transform
        x = vPoint.x(), y = vPoint.y(); z = vPoint.z();
        if ( ct )
        {
          ct->transformInPlace( x, y, z );
        }
        mapPoint.setX( x ); mapPoint.setY( y );
        mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
        if ( mRotateMarker )
        {
          double angle = context.renderContext().geometry()->vertexAngle( vId );
          mMarker->setAngle( angle * 180 / M_PI );
        }
        mMarker->renderPoint( mapPoint, context.feature(), rc, -1, context.selected() );
      }
    }
    return;
  }

  if ( placement == FirstVertex )
  {
    i = 0;
    maxCount = 1;
  }
  else if ( placement == LastVertex )
  {
    i = points.count() - 1;
    maxCount = points.count();
  }
  else if ( placement == Vertex )
  {
    i = 0;
    maxCount = points.count();
    if ( points.first() == points.last() )
      isRing = true;
  }
  else
  {
    return;
  }

  if ( offsetAlongLine > 0 && ( placement == FirstVertex || placement == LastVertex ) )
  {
    double distance;
    distance = placement == FirstVertex ? offsetAlongLine : -offsetAlongLine;
    renderOffsetVertexAlongLine( points, i, distance, context );
    // restore original rotation
    mMarker->setAngle( origAngle );
    return;
  }

  for ( ; i < maxCount; ++i )
  {
    if ( isRing && placement == Vertex && i == points.count() - 1 )
    {
      continue; // don't draw the last marker - it has been drawn already
    }
    // rotate marker (if desired)
    if ( mRotateMarker )
    {
      double angle = markerAngle( points, isRing, i );
      mMarker->setAngle( origAngle + angle * 180 / M_PI );
    }

    mMarker->renderPoint( points.at( i ), context.feature(), rc, -1, context.selected() );
  }

  // restore original rotation
  mMarker->setAngle( origAngle );
}
void QgsMarkerLineSymbolLayerV2::renderPolylineInterval( const QPolygonF& points, QgsSymbolV2RenderContext& context )
{
  if ( points.isEmpty() )
    return;

  QPointF lastPt = points[0];
  double lengthLeft = 0; // how much is left until next marker
  bool first = mOffsetAlongLine ? false : true; //only draw marker at first vertex when no offset along line is set

  QgsRenderContext& rc = context.renderContext();
  double interval = mInterval;

  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_INTERVAL ) )
  {
    context.setOriginalValueVariable( mInterval );
    interval = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_INTERVAL, context, mInterval ).toDouble();
  }
  if ( interval <= 0 )
  {
    interval = 0.1;
  }
  double offsetAlongLine = mOffsetAlongLine;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET_ALONG_LINE ) )
  {
    context.setOriginalValueVariable( mOffsetAlongLine );
    offsetAlongLine = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET_ALONG_LINE, context, mOffsetAlongLine ).toDouble();
  }

  double painterUnitInterval = QgsSymbolLayerV2Utils::convertToPainterUnits( rc, interval, mIntervalUnit, mIntervalMapUnitScale );
  lengthLeft = painterUnitInterval - QgsSymbolLayerV2Utils::convertToPainterUnits( rc, offsetAlongLine, mIntervalUnit, mIntervalMapUnitScale );

  for ( int i = 1; i < points.count(); ++i )
  {
    const QPointF& pt = points[i];

    if ( lastPt == pt ) // must not be equal!
      continue;

    // for each line, find out dx and dy, and length
    MyLine l( lastPt, pt );
    QPointF diff = l.diffForInterval( painterUnitInterval );

    // if there's some length left from previous line
    // use only the rest for the first point in new line segment
    double c = 1 - lengthLeft / painterUnitInterval;

    lengthLeft += l.length();

    // rotate marker (if desired)
    if ( mRotateMarker )
    {
      mMarker->setLineAngle( l.angle() * 180 / M_PI );
    }

    // draw first marker
    if ( first )
    {
      mMarker->renderPoint( lastPt, context.feature(), rc, -1, context.selected() );
      first = false;
    }

    // while we're not at the end of line segment, draw!
    while ( lengthLeft > painterUnitInterval )
    {
      // "c" is 1 for regular point or in interval (0,1] for begin of line segment
      lastPt += c * diff;
      lengthLeft -= painterUnitInterval;
      mMarker->renderPoint( lastPt, context.feature(), rc, -1, context.selected() );
      c = 1; // reset c (if wasn't 1 already)
    }

    lastPt = pt;
  }
}
void QgsMarkerLineSymbolLayerV2::renderPolyline( const QPolygonF& points, QgsSymbolV2RenderContext& context )
{
  double offset = mOffset;

  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET ) )
  {
    context.setOriginalValueVariable( mOffset );
    offset = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET, context, mOffset ).toDouble();
  }

  Placement placement = mPlacement;

  bool ok;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_PLACEMENT ) )
  {
    QString placementString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_PLACEMENT, context, QVariant(), &ok ).toString();
    if ( ok )
    {
      if ( placementString.compare( "vertex", Qt::CaseInsensitive ) == 0 )
      {
        placement = Vertex;
      }
      else if ( placementString.compare( "lastvertex", Qt::CaseInsensitive ) == 0 )
      {
        placement = LastVertex;
      }
      else if ( placementString.compare( "firstvertex", Qt::CaseInsensitive ) == 0 )
      {
        placement = FirstVertex;
      }
      else if ( placementString.compare( "centerpoint", Qt::CaseInsensitive ) == 0 )
      {
        placement = CentralPoint;
      }
      else if ( placementString.compare( "curvepoint", Qt::CaseInsensitive ) == 0 )
      {
        placement = CurvePoint;
      }
      else
      {
        placement = Interval;
      }
    }
  }

  if ( offset == 0 )
  {
    if ( placement == Interval )
      renderPolylineInterval( points, context );
    else if ( placement == CentralPoint )
      renderPolylineCentral( points, context );
    else
      renderPolylineVertex( points, context, placement );
  }
  else
  {
    context.renderContext().setGeometry( 0 ); //always use segmented geometry with offset
    QList<QPolygonF> mline = ::offsetLine( points, QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), offset, mOffsetUnit, mOffsetMapUnitScale ), context.feature() ? context.feature()->constGeometry()->type() : QGis::Line );

    for ( int part = 0; part < mline.count(); ++part )
    {
      const QPolygonF &points2 = mline[ part ];

      if ( placement == Interval )
        renderPolylineInterval( points2, context );
      else if ( placement == CentralPoint )
        renderPolylineCentral( points2, context );
      else
        renderPolylineVertex( points2, context, placement );
    }
  }
}
void QgsSimpleLineSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, QPen& pen, QPen& selPen, double& offset )
{
  if ( !hasDataDefinedProperties() )
    return; // shortcut

  //data defined properties
  bool hasStrokeWidthExpression = false;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH ) )
  {
    context.setOriginalValueVariable( mWidth );
    double scaledWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(),
                         evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, context, mWidth ).toDouble(),
                         mWidthUnit, mWidthMapUnitScale );
    pen.setWidthF( scaledWidth );
    selPen.setWidthF( scaledWidth );
    hasStrokeWidthExpression = true;
  }

  //color
  bool ok;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_COLOR ) )
  {
    context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodeColor( pen.color() ) );
    QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_COLOR, context, QVariant(), &ok ).toString();
    if ( ok )
      pen.setColor( QgsSymbolLayerV2Utils::decodeColor( colorString ) );
  }

  //offset
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET ) )
  {
    context.setOriginalValueVariable( mOffset );
    offset = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET, context, offset ).toDouble();
  }

  //dash dot vector
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_CUSTOMDASH ) )
  {
    double scaledWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mWidth, mWidthUnit, mWidthMapUnitScale );
    double dashWidthDiv = mPen.widthF();

    if ( hasStrokeWidthExpression )
    {
      dashWidthDiv = pen.widthF();
      scaledWidth = pen.widthF();
    }

    //fix dash pattern width in Qt 4.8
    QStringList versionSplit = QString( qVersion() ).split( '.' );
    if ( versionSplit.size() > 1
         && versionSplit.at( 1 ).toInt() >= 8
         && ( scaledWidth * context.renderContext().rasterScaleFactor() ) < 1.0 )
    {
      dashWidthDiv = 1.0;
    }

    QVector<qreal> dashVector;
    QStringList dashList = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_CUSTOMDASH, context, QVariant(), &ok ).toString().split( ';' );
    if ( ok )
    {
      QStringList::const_iterator dashIt = dashList.constBegin();
      for ( ; dashIt != dashList.constEnd(); ++dashIt )
      {
        dashVector.push_back( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), dashIt->toDouble(), mCustomDashPatternUnit, mCustomDashPatternMapUnitScale ) / dashWidthDiv );
      }
      pen.setDashPattern( dashVector );
    }
  }

  //line style
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_LINE_STYLE ) )
  {
    context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodePenStyle( pen.style() ) );
    QString lineStyleString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_LINE_STYLE, context, QVariant(), &ok ).toString();
    if ( ok )
      pen.setStyle( QgsSymbolLayerV2Utils::decodePenStyle( lineStyleString ) );
  }

  //join style
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_JOINSTYLE ) )
  {
    context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodePenJoinStyle( pen.joinStyle() ) );
    QString joinStyleString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_JOINSTYLE, context, QVariant(), &ok ).toString();
    if ( ok )
      pen.setJoinStyle( QgsSymbolLayerV2Utils::decodePenJoinStyle( joinStyleString ) );
  }

  //cap style
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_CAPSTYLE ) )
  {
    context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodePenCapStyle( pen.capStyle() ) );
    QString capStyleString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_CAPSTYLE, context, QVariant(), &ok ).toString();
    if ( ok )
      pen.setCapStyle( QgsSymbolLayerV2Utils::decodePenCapStyle( capStyleString ) );
  }
}
void QgsEllipseSymbolLayerV2::preparePath( const QString& symbolName, QgsSymbolV2RenderContext& context, double* scaledWidth, double* scaledHeight, const QgsFeature* )
{
  mPainterPath = QPainterPath();
  const QgsRenderContext& ct = context.renderContext();

  double width = 0;

  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH ) ) //1. priority: data defined setting on symbol layer le
  {
    context.setOriginalValueVariable( mSymbolWidth );
    width = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, context, mSymbolWidth ).toDouble();
  }
  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
  {
    width = mSize;
  }
  else //3. priority: global width setting
  {
    width = mSymbolWidth;
  }
  if ( scaledWidth )
  {
    *scaledWidth = width;
  }
  width = QgsSymbolLayerV2Utils::convertToPainterUnits( ct, width, mSymbolWidthUnit, mSymbolHeightMapUnitScale );

  double height = 0;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT ) ) //1. priority: data defined setting on symbol layer level
  {
    context.setOriginalValueVariable( mSymbolHeight );
    height = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT, context, mSymbolHeight ).toDouble();
  }
  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
  {
    height = mSize;
  }
  else //3. priority: global height setting
  {
    height = mSymbolHeight;
  }
  if ( scaledHeight )
  {
    *scaledHeight = height;
  }
  height = QgsSymbolLayerV2Utils::convertToPainterUnits( ct, height, mSymbolHeightUnit, mSymbolHeightMapUnitScale );

  if ( symbolName == "circle" )
  {
    mPainterPath.addEllipse( QRectF( -width / 2.0, -height / 2.0, width, height ) );
  }
  else if ( symbolName == "rectangle" )
  {
    mPainterPath.addRect( QRectF( -width / 2.0, -height / 2.0, width, height ) );
  }
  else if ( symbolName == "cross" )
  {
    mPainterPath.moveTo( 0, -height / 2.0 );
    mPainterPath.lineTo( 0, height / 2.0 );
    mPainterPath.moveTo( -width / 2.0, 0 );
    mPainterPath.lineTo( width / 2.0, 0 );
  }
  else if ( symbolName == "triangle" )
  {
    mPainterPath.moveTo( 0, -height / 2.0 );
    mPainterPath.lineTo( -width / 2.0, height / 2.0 );
    mPainterPath.lineTo( width / 2.0, height / 2.0 );
    mPainterPath.lineTo( 0, -height / 2.0 );
  }
}
void QgsEllipseSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context )
{
  bool ok;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH ) )
  {
    context.setOriginalValueVariable( mOutlineWidth );
    double width = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
    width = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), width, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
    mPen.setWidthF( width );
  }
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_STYLE ) )
  {
    context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodePenStyle( mPen.style() ) );
    QString styleString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_STYLE, context, QVariant(), &ok ).toString();
    if ( ok )
    {
      Qt::PenStyle style = QgsSymbolLayerV2Utils::decodePenStyle( styleString );
      mPen.setStyle( style );
    }
  }
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_FILL_COLOR ) )
  {
    context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodeColor( mBrush.color() ) );
    QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_FILL_COLOR, context, QVariant(), &ok ).toString();
    if ( ok )
      mBrush.setColor( QgsSymbolLayerV2Utils::decodeColor( colorString ) );
  }
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_COLOR ) )
  {
    context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodeColor( mPen.color() ) );
    QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_COLOR, context, QVariant(), &ok ).toString();
    if ( ok )
      mPen.setColor( QgsSymbolLayerV2Utils::decodeColor( colorString ) );
  }
  double scaledWidth = mSymbolWidth;
  double scaledHeight = mSymbolHeight;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH ) || hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT ) || hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_SYMBOL_NAME ) )
  {
    QString symbolName =  mSymbolName;
    if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_SYMBOL_NAME ) )
    {
      context.setOriginalValueVariable( mSymbolName );
      symbolName = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SYMBOL_NAME, context, mSymbolName ).toString();
    }
    preparePath( symbolName, context, &scaledWidth, &scaledHeight, context.feature() );
  }

  //offset
  double offsetX = 0;
  double offsetY = 0;
  markerOffset( context, scaledWidth, scaledHeight, mSymbolWidthUnit, mSymbolHeightUnit, offsetX, offsetY, mSymbolWidthMapUnitScale, mSymbolHeightMapUnitScale );
  QPointF off( offsetX, offsetY );

  QPainter* p = context.renderContext().painter();
  if ( !p )
  {
    return;
  }

  //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
  double rotation = 0.0;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_ROTATION ) )
  {
    context.setOriginalValueVariable( mAngle );
    rotation = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_ROTATION, context, mAngle ).toDouble() + mLineAngle;
  }
  else if ( !qgsDoubleNear( mAngle + mLineAngle, 0.0 ) )
  {
    rotation = mAngle + mLineAngle;
  }
  if ( rotation )
    off = _rotatedOffset( off, rotation );

  QMatrix transform;
  transform.translate( point.x() + off.x(), point.y() + off.y() );
  if ( !qgsDoubleNear( rotation, 0.0 ) )
  {
    transform.rotate( rotation );
  }

  p->setPen( mPen );
  p->setBrush( mBrush );
  p->drawPath( transform.map( mPainterPath ) );
}
bool QgsEllipseSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext &context, QPointF shift ) const
{
  //width
  double symbolWidth = mSymbolWidth;

  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH ) ) //1. priority: data defined setting on symbol layer le
  {
    context.setOriginalValueVariable( mSymbolWidth );
    symbolWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, context, mSymbolWidth ).toDouble();
  }
  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
  {
    symbolWidth = mSize;
  }
  if ( mSymbolWidthUnit == QgsSymbolV2::MM )
  {
    symbolWidth *= mmMapUnitScaleFactor;
  }

  //height
  double symbolHeight = mSymbolHeight;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT ) ) //1. priority: data defined setting on symbol layer level
  {
    context.setOriginalValueVariable( mSymbolHeight );
    symbolHeight = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT, context, mSymbolHeight ).toDouble();
  }
  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
  {
    symbolHeight = mSize;
  }
  if ( mSymbolHeightUnit == QgsSymbolV2::MM )
  {
    symbolHeight *= mmMapUnitScaleFactor;
  }

  //outline width
  double outlineWidth = mOutlineWidth;

  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH ) )
  {
    context.setOriginalValueVariable( mOutlineWidth );
    outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
  }
  if ( mOutlineWidthUnit == QgsSymbolV2::MM )
  {
    outlineWidth *= outlineWidth;
  }

  //fill color
  bool ok;
  QColor fc = mColor;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_FILL_COLOR ) )
  {
    context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodeColor( mColor ) );
    QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_FILL_COLOR, context, QVariant(), &ok ).toString();
    if ( ok )
      fc = QgsSymbolLayerV2Utils::decodeColor( colorString );
  }

  //outline color
  QColor oc = mOutlineColor;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_COLOR ) )
  {
    context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodeColor( mOutlineColor ) );
    QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_COLOR, context, QVariant(), &ok ).toString();
    if ( ok )
      oc = QgsSymbolLayerV2Utils::decodeColor( colorString );
  }

  //symbol name
  QString symbolName = mSymbolName;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_SYMBOL_NAME ) )
  {
    context.setOriginalValueVariable( mSymbolName );
    symbolName = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SYMBOL_NAME, context, mSymbolName ).toString();
  }

  //offset
  double offsetX = 0;
  double offsetY = 0;
  markerOffset( context, offsetX, offsetY );
  QPointF off( offsetX, offsetY );

  //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
  double rotation = 0.0;
  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_ROTATION ) )
  {
    context.setOriginalValueVariable( mAngle );
    rotation = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_ROTATION, context, mAngle ).toDouble() + mLineAngle;
  }
  else if ( !qgsDoubleNear( mAngle + mLineAngle, 0.0 ) )
  {
    rotation = mAngle + mLineAngle;
  }
  rotation = -rotation; //rotation in Qt is counterclockwise
  if ( rotation )
    off = _rotatedOffset( off, rotation );

  QTransform t;
  t.translate( shift.x() + offsetX, shift.y() + offsetY );

  if ( !qgsDoubleNear( rotation, 0.0 ) )
    t.rotate( rotation );

  double halfWidth = symbolWidth / 2.0;
  double halfHeight = symbolHeight / 2.0;

  if ( symbolName == "circle" )
  {
    if ( qgsDoubleNear( halfWidth, halfHeight ) )
    {
      QgsPointV2 pt( t.map( QPointF( 0, 0 ) ) );
      e.writeFilledCircle( layerName, oc, pt, halfWidth );
    }
    else
    {
      QgsPointSequenceV2 line;

      double stepsize = 2 * M_PI / 40;
      for ( int i = 0; i < 39; ++i )
      {
        double angle = stepsize * i;
        double x = halfWidth * cos( angle );
        double y = halfHeight * sin( angle );
        line << QgsPointV2( t.map( QPointF( x, y ) ) );
      }
      //close ellipse with first point
      line << line.at( 0 );

      if ( mBrush.style() != Qt::NoBrush )
        e.writePolygon( QgsRingSequenceV2() << line, layerName, "SOLID", fc );
      if ( mPen.style() != Qt::NoPen )
        e.writePolyline( line, layerName, "CONTINUOUS", oc, outlineWidth );
    }
  }
  else if ( symbolName == "rectangle" )
  {
    QgsPointSequenceV2 p;
    p << QgsPointV2( t.map( QPointF( -halfWidth, -halfHeight ) ) )
    << QgsPointV2( t.map( QPointF( halfWidth, -halfHeight ) ) )
    << QgsPointV2( t.map( QPointF( halfWidth, halfHeight ) ) )
    << QgsPointV2( t.map( QPointF( -halfWidth, halfHeight ) ) );
    p << p[0];

    if ( mBrush.style() != Qt::NoBrush )
      e.writePolygon( QgsRingSequenceV2() << p, layerName, "SOLID", fc );
    if ( mPen.style() != Qt::NoPen )
      e.writePolyline( p, layerName, "CONTINUOUS", oc, outlineWidth );
    return true;
  }
  else if ( symbolName == "cross" && mPen.style() != Qt::NoPen )
  {
    e.writePolyline( QgsPointSequenceV2()
                     << QgsPointV2( t.map( QPointF( -halfWidth, 0 ) ) )
                     << QgsPointV2( t.map( QPointF( halfWidth, 0 ) ) ),
                     layerName, "CONTINUOUS", oc, outlineWidth );
    e.writePolyline( QgsPointSequenceV2()
                     << QgsPointV2( t.map( QPointF( 0, halfHeight ) ) )
                     << QgsPointV2( t.map( QPointF( 0, -halfHeight ) ) ),
                     layerName, "CONTINUOUS", oc, outlineWidth );
    return true;
  }
  else if ( symbolName == "triangle" )
  {
    QgsPointSequenceV2 p;
    p << QgsPointV2( t.map( QPointF( -halfWidth, -halfHeight ) ) )
    << QgsPointV2( t.map( QPointF( halfWidth, -halfHeight ) ) )
    << QgsPointV2( t.map( QPointF( 0, halfHeight ) ) );
    p << p[0];
    if ( mBrush.style() != Qt::NoBrush )
      e.writePolygon( QgsRingSequenceV2() << p, layerName, "SOLID", fc );
    if ( mPen.style() != Qt::NoPen )
      e.writePolyline( p, layerName, "CONTINUOUS", oc, outlineWidth );
    return true;
  }

  return false; //soon...
}