void QgsSimpleLineSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context ) { QColor penColor = mColor; penColor.setAlphaF( context.alpha() ); mPen.setColor( penColor ); double scaledWidth = context.outputLineWidth( mWidth ); mPen.setWidthF( scaledWidth ); if ( mUseCustomDashPattern && scaledWidth != 0 ) { mPen.setStyle( Qt::CustomDashLine ); //scale pattern vector QVector<qreal> scaledVector; QVector<qreal>::const_iterator it = mCustomDashVector.constBegin(); for ( ; it != mCustomDashVector.constEnd(); ++it ) { //the dash is specified in terms of pen widths, therefore the division scaledVector << context.outputLineWidth(( *it ) / scaledWidth ); } mPen.setDashPattern( scaledVector ); } else { mPen.setStyle( mPenStyle ); } mPen.setJoinStyle( mPenJoinStyle ); mPen.setCapStyle( mPenCapStyle ); mSelPen = mPen; QColor selColor = context.selectionColor(); if ( ! selectionIsOpaque ) selColor.setAlphaF( context.alpha() ); mSelPen.setColor( selColor ); }
void QgsFontMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context ) { QPainter* p = context.renderContext().painter(); QColor penColor = context.selected() ? context.selectionColor() : mColor; penColor.setAlphaF( context.alpha() ); p->setPen( penColor ); p->setFont( mFont ); p->save(); QPointF outputOffset = QPointF( context.outputLineWidth( mOffset.x() ), context.outputLineWidth( mOffset.y() ) ); if ( mAngle ) outputOffset = _rotatedOffset( outputOffset, mAngle ); p->translate( point + outputOffset ); if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) { double s = mSize / mOrigSize; p->scale( s, s ); } if ( mAngle != 0 ) p->rotate( mAngle ); p->drawText( -mChrOffset, mChr ); p->restore(); }
void QgsSimpleLineSymbolLayerV2::renderPolyline( const QPolygonF& points, QgsSymbolV2RenderContext& context ) { QPainter* p = context.renderContext().painter(); if ( !p ) { return; } if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) { double scaledWidth = context.outputLineWidth( mWidth ); mPen.setWidthF( scaledWidth ); mSelPen.setWidthF( scaledWidth ); } p->setPen( context.selected() ? mSelPen : mPen ); if ( mOffset == 0 ) { p->drawPolyline( points ); } else { double scaledOffset = context.outputLineWidth( mOffset ); p->drawPolyline( ::offsetLine( points, scaledOffset ) ); } }
void QgsVectorFieldSymbolLayer::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context ) { if ( !mLineSymbol ) { return; } const QgsFeature* f = context.feature(); if ( !f ) { //preview QPolygonF line; line << QPointF( 0, 50 ); line << QPointF( 100, 50 ); mLineSymbol->renderPolyline( line, 0, context.renderContext() ); } double xComponent = 0; double yComponent = 0; double xVal = 0; if ( mXIndex != -1 ) { xVal = f->attributeMap()[mXIndex].toDouble(); } double yVal = 0; if ( mYIndex != -1 ) { yVal = f->attributeMap()[mYIndex].toDouble(); } switch ( mVectorFieldType ) { case Cartesian: xComponent = context.outputLineWidth( xVal ); yComponent = context.outputLineWidth( yVal ); break; case Polar: convertPolarToCartesian( xVal, yVal, xComponent, yComponent ); xComponent = context.outputLineWidth( xComponent ); yComponent = context.outputLineWidth( yComponent ); break; case Height: xComponent = 0; yComponent = context.outputLineWidth( yVal ); break; default: break; } xComponent *= mScale; yComponent *= mScale; QPolygonF line; line << point; line << QPointF( point.x() + xComponent, point.y() - yComponent ); mLineSymbol->renderPolyline( line, f, context.renderContext() ); }
void QgsLineDecorationSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context ) { QColor penColor = mColor; penColor.setAlphaF( context.alpha() ); mPen.setWidth( context.outputLineWidth( mWidth ) ); mPen.setColor( penColor ); QColor selColor = context.selectionColor(); if ( ! selectionIsOpaque ) selColor.setAlphaF( context.alpha() ); mSelPen.setWidth( context.outputLineWidth( mWidth ) ); mSelPen.setColor( selColor ); }
void QgsLineDecorationSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context ) { QColor penColor = mColor; penColor.setAlphaF( mColor.alphaF() * context.alpha() ); double width = mWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mWidthUnit ); mPen.setWidth( context.outputLineWidth( width ) ); mPen.setColor( penColor ); QColor selColor = context.renderContext().selectionColor(); if ( ! selectionIsOpaque ) selColor.setAlphaF( context.alpha() ); mSelPen.setWidth( context.outputLineWidth( width ) ); mSelPen.setColor( selColor ); }
void QgsLineDecorationSymbolLayerV2::renderPolyline( const QPolygonF& points, QgsSymbolV2RenderContext& context ) { // draw arrow at the end of line QPainter* p = context.renderContext().painter(); if ( !p ) { return; } int cnt = points.count(); QPointF p2 = points.at( --cnt ); QPointF p1 = points.at( --cnt ); while ( p2 == p1 && cnt ) p1 = points.at( --cnt ); if ( p1 == p2 ) { // this is a collapsed line... don't bother drawing an arrow // with arbitrary orientation return; } double angle = atan2( p2.y() - p1.y(), p2.x() - p1.x() ); double size = context.outputLineWidth( mWidth * 8 ); double angle1 = angle + M_PI / 6; double angle2 = angle - M_PI / 6; QPointF p2_1 = p2 - QPointF( size * cos( angle1 ), size * sin( angle1 ) ); QPointF p2_2 = p2 - QPointF( size * cos( angle2 ), size * sin( angle2 ) ); p->setPen( context.selected() ? mSelPen : mPen ); p->drawLine( p2, p2_1 ); p->drawLine( p2, p2_2 ); }
void QgsSimpleFillSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context ) { QColor fillColor = mColor; fillColor.setAlphaF( context.alpha() * mColor.alphaF() ); mBrush = QBrush( fillColor, mBrushStyle ); // scale brush content for printout double rasterScaleFactor = context.renderContext().rasterScaleFactor(); if ( rasterScaleFactor != 1.0 ) { mBrush.setMatrix( QMatrix().scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor ) ); } QColor selColor = context.selectionColor(); QColor selPenColor = selColor == mColor ? selColor : mBorderColor; if ( ! selectionIsOpaque ) selColor.setAlphaF( context.alpha() ); mSelBrush = QBrush( selColor ); // N.B. unless a "selection line color" is implemented in addition to the "selection color" option // this would mean symbols with "no fill" look the same whether or not they are selected if ( selectFillStyle ) mSelBrush.setStyle( mBrushStyle ); QColor borderColor = mBorderColor; borderColor.setAlphaF( context.alpha() * mBorderColor.alphaF() ); mPen = QPen( borderColor ); mSelPen = QPen( selPenColor ); mPen.setStyle( mBorderStyle ); mPen.setWidthF( context.outputLineWidth( mBorderWidth ) ); }
void QgsFontMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context ) { mFont = QFont( mFontFamily ); mFont.setPixelSize( context.outputLineWidth( mSize ) ); QFontMetrics fm( mFont ); mChrOffset = QPointF( fm.width( mChr ) / 2, -fm.ascent() / 2 ); mOrigSize = mSize; // save in case the size would be data defined }
void QgsPointDisplacementRenderer::drawCircle( double radiusPainterUnits, QgsSymbolV2RenderContext& context, const QPointF& centerPoint, int nSymbols ) { QPainter* p = context.renderContext().painter(); if ( nSymbols < 2 || !p ) //draw circle only if multiple features { return; } //draw Circle QPen circlePen( mCircleColor ); circlePen.setWidthF( context.outputLineWidth( mCircleWidth ) ); p->setPen( circlePen ); p->drawArc( QRectF( centerPoint.x() - radiusPainterUnits, centerPoint.y() - radiusPainterUnits, 2 * radiusPainterUnits, 2 * radiusPainterUnits ), 0, 5760 ); }
void QgsPointDisplacementRenderer::drawLabels( const QPointF& centerPoint, QgsSymbolV2RenderContext& context, const QList<QPointF>& labelShifts, const QStringList& labelList ) { QPainter* p = context.renderContext().painter(); if ( !p ) { return; } QPen labelPen( mLabelColor ); p->setPen( labelPen ); //scale font (for printing) QFont pixelSizeFont = mLabelFont; pixelSizeFont.setPixelSize( context.outputLineWidth( mLabelFont.pointSizeF() * 0.3527 ) ); QFont scaledFont = pixelSizeFont; scaledFont.setPixelSize( pixelSizeFont.pixelSize() * context.renderContext().rasterScaleFactor() ); p->setFont( scaledFont ); QFontMetricsF fontMetrics( pixelSizeFont ); QPointF currentLabelShift; //considers the signs to determine the label position QList<QPointF>::const_iterator labelPosIt = labelShifts.constBegin(); QStringList::const_iterator text_it = labelList.constBegin(); for ( ; labelPosIt != labelShifts.constEnd() && text_it != labelList.constEnd(); ++labelPosIt, ++text_it ) { currentLabelShift = *labelPosIt; if ( currentLabelShift.x() < 0 ) { currentLabelShift.setX( currentLabelShift.x() - fontMetrics.width( *text_it ) ); } if ( currentLabelShift.y() > 0 ) { currentLabelShift.setY( currentLabelShift.y() + fontMetrics.ascent() ); } QPointF drawingPoint( centerPoint + currentLabelShift ); p->save(); p->translate( drawingPoint.x(), drawingPoint.y() ); p->scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() ); p->drawText( QPointF( 0, 0 ), *text_it ); p->restore(); } }
void QgsMarkerLineSymbolLayerV2::renderPolyline( const QPolygonF& points, QgsSymbolV2RenderContext& context ) { if ( mOffset == 0 ) { if ( mPlacement == Interval ) renderPolylineInterval( points, context ); else if ( mPlacement == CentralPoint ) renderPolylineCentral( points, context ); else renderPolylineVertex( points, context ); } else { QPolygonF points2 = ::offsetLine( points, context.outputLineWidth( mOffset ) ); if ( mPlacement == Interval ) renderPolylineInterval( points2, context ); else if ( mPlacement == CentralPoint ) renderPolylineCentral( points2, context ); else renderPolylineVertex( points2, context ); } }
void QgsSimpleMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context ) { QgsRenderContext& rc = context.renderContext(); QPainter* p = rc.painter(); if ( !p ) { return; } QPointF off( context.outputLineWidth( mOffset.x() ), context.outputLineWidth( mOffset.y() ) ); if ( mAngle ) off = _rotatedOffset( off, mAngle ); if ( mUsingCache ) { // we will use cached image QImage &img = context.selected() ? mSelCache : mCache; double s = img.width() / context.renderContext().rasterScaleFactor(); p->drawImage( QRectF( point.x() - s / 2.0 + off.x(), point.y() - s / 2.0 + off.y(), s, s ), img ); } else { QMatrix transform; bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation; bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale; // move to the desired position transform.translate( point.x() + off.x(), point.y() + off.y() ); // resize if necessary if ( hasDataDefinedSize ) { double scaledSize = context.outputLineWidth( mSize ); switch ( mScaleMethod ) { case QgsSymbolV2::ScaleArea: scaledSize = sqrt( scaledSize ); break; case QgsSymbolV2::ScaleDiameter: break; } double half = scaledSize / 2.0; transform.scale( half, half ); } // rotate if necessary if ( mAngle != 0 && hasDataDefinedRotation ) { transform.rotate( mAngle ); } p->setBrush( context.selected() ? mSelBrush : mBrush ); p->setPen( context.selected() ? mSelPen : mPen ); if ( !mPolygon.isEmpty() ) p->drawPolygon( transform.map( mPolygon ) ); else p->drawPath( transform.map( mPath ) ); } }
void QgsSimpleMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context ) { QColor brushColor = mColor; QColor penColor = mBorderColor; brushColor.setAlphaF( mColor.alphaF() * context.alpha() ); penColor.setAlphaF( mBorderColor.alphaF() * context.alpha() ); mBrush = QBrush( brushColor ); mPen = QPen( penColor ); mPen.setWidthF( context.outputLineWidth( mPen.widthF() ) ); QColor selBrushColor = context.selectionColor(); QColor selPenColor = selBrushColor == mColor ? selBrushColor : mBorderColor; if ( context.alpha() < 1 ) { selBrushColor.setAlphaF( context.alpha() ); selPenColor.setAlphaF( context.alpha() ); } mSelBrush = QBrush( selBrushColor ); mSelPen = QPen( selPenColor ); mSelPen.setWidthF( context.outputLineWidth( mPen.widthF() ) ); bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation; bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale; // use caching only when: // - the size and rotation is not data-defined // - drawing to screen (not printer) mUsingCache = !hasDataDefinedRotation && !hasDataDefinedSize && !context.renderContext().forceVectorOutput(); // use either QPolygonF or QPainterPath for drawing // TODO: find out whether drawing directly doesn't bring overhead - if not, use it for all shapes if ( !prepareShape() ) // drawing as a polygon { if ( preparePath() ) // drawing as a painter path { // some markers can't be drawn as a polygon (circle, cross) // For these set the selected border color to the selected color if ( mName != "circle" ) mSelPen.setColor( selBrushColor ); } else { QgsDebugMsg( "unknown symbol" ); return; } } QMatrix transform; // scale the shape (if the size is not going to be modified) if ( !hasDataDefinedSize ) { double scaledSize = context.outputLineWidth( mSize ); if ( mUsingCache ) scaledSize *= context.renderContext().rasterScaleFactor(); double half = scaledSize / 2.0; transform.scale( half, half ); } // rotate if the rotation is not going to be changed during the rendering if ( !hasDataDefinedRotation && mAngle != 0 ) { transform.rotate( mAngle ); } if ( !mPolygon.isEmpty() ) mPolygon = transform.map( mPolygon ); else mPath = transform.map( mPath ); if ( mUsingCache ) { prepareCache( context ); } else { mCache = QImage(); mSelCache = QImage(); } }
void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolV2RenderContext& symbolContext, const QPointF& centerPoint, int nPosition, double symbolDiagonal, QList<QPointF>& symbolPositions, QList<QPointF>& labelShifts, double& circleRadius ) const { symbolPositions.clear(); labelShifts.clear(); if ( nPosition < 1 ) { return; } else if ( nPosition == 1 ) //If there is only one feature, draw it exactly at the center position { symbolPositions.append( centerPoint ); labelShifts.append( QPointF( symbolDiagonal / 2.0, -symbolDiagonal / 2.0 ) ); return; } double circleAdditionPainterUnits = symbolContext.outputLineWidth( mCircleRadiusAddition ); switch ( mPlacement ) { case Ring: { double minDiameterToFitSymbols = nPosition * symbolDiagonal / ( 2.0 * M_PI ); double radius = qMax( symbolDiagonal / 2, minDiameterToFitSymbols ) + circleAdditionPainterUnits; double fullPerimeter = 2 * M_PI; double angleStep = fullPerimeter / nPosition; for ( double currentAngle = 0.0; currentAngle < fullPerimeter; currentAngle += angleStep ) { double sinusCurrentAngle = sin( currentAngle ); double cosinusCurrentAngle = cos( currentAngle ); QPointF positionShift( radius * sinusCurrentAngle, radius * cosinusCurrentAngle ); QPointF labelShift(( radius + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radius + symbolDiagonal / 2 ) * cosinusCurrentAngle ); symbolPositions.append( centerPoint + positionShift ); labelShifts.append( labelShift ); } circleRadius = radius; break; } case ConcentricRings: { double centerDiagonal = QgsSymbolLayerV2Utils::convertToPainterUnits( symbolContext.renderContext(), M_SQRT2 * mCenterSymbol->size(), mCenterSymbol->outputUnit(), mCenterSymbol->mapUnitScale() ); int pointsRemaining = nPosition; int ringNumber = 1; double firstRingRadius = centerDiagonal / 2.0 + symbolDiagonal / 2.0; while ( pointsRemaining > 0 ) { double radiusCurrentRing = qMax( firstRingRadius + ( ringNumber - 1 ) * symbolDiagonal + ringNumber * circleAdditionPainterUnits, 0.0 ); int maxPointsCurrentRing = qMax( floor( 2 * M_PI * radiusCurrentRing / symbolDiagonal ), 1.0 ); int actualPointsCurrentRing = qMin( maxPointsCurrentRing, pointsRemaining ); double angleStep = 2 * M_PI / actualPointsCurrentRing; double currentAngle = 0.0; for ( int i = 0; i < actualPointsCurrentRing; ++i ) { double sinusCurrentAngle = sin( currentAngle ); double cosinusCurrentAngle = cos( currentAngle ); QPointF positionShift( radiusCurrentRing * sinusCurrentAngle, radiusCurrentRing * cosinusCurrentAngle ); QPointF labelShift(( radiusCurrentRing + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radiusCurrentRing + symbolDiagonal / 2 ) * cosinusCurrentAngle ); symbolPositions.append( centerPoint + positionShift ); labelShifts.append( labelShift ); currentAngle += angleStep; } pointsRemaining -= actualPointsCurrentRing; ringNumber++; circleRadius = radiusCurrentRing; } break; } } }
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 = true; double origAngle = mMarker->angle(); double painterUnitInterval = context.outputLineWidth( mInterval > 0 ? mInterval : 0.1 ); QgsRenderContext& rc = context.renderContext(); 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->setAngle( origAngle + ( l.angle() * 180 / M_PI ) ); } // draw first marker if ( first ) { mMarker->renderPoint( lastPt, 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, rc, -1, context.selected() ); c = 1; // reset c (if wasn't 1 already) } lastPt = pt; } // restore original rotation mMarker->setAngle( origAngle ); }
void QgsSvgMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context ) { QPainter* p = context.renderContext().painter(); if ( !p ) { return; } double size = context.outputLineWidth( mSize ); //don't render symbols with size below one or above 10,000 pixels if (( int )size < 1 || 10000.0 < size ) { return; } p->save(); QPointF outputOffset = QPointF( context.outputLineWidth( mOffset.x() ), context.outputLineWidth( mOffset.y() ) ); if ( mAngle ) outputOffset = _rotatedOffset( outputOffset, mAngle ); p->translate( point + outputOffset ); bool rotated = !doubleNear( mAngle, 0 ); bool drawOnScreen = doubleNear( context.renderContext().rasterScaleFactor(), 1.0, 0.1 ); if ( rotated ) p->rotate( mAngle ); bool fitsInCache = true; bool usePict = true; double hwRatio = 1.0; if ( drawOnScreen && !rotated ) { usePict = false; const QImage& img = QgsSvgCache::instance()->svgAsImage( mPath, size, mFillColor, mOutlineColor, mOutlineWidth, context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache ); if ( fitsInCache && img.width() > 1 ) { //consider transparency if ( !doubleNear( context.alpha(), 1.0 ) ) { QImage transparentImage = img.copy(); QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() ); p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage ); hwRatio = ( double )transparentImage.height() / ( double )transparentImage.width(); } else { p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img ); hwRatio = ( double )img.height() / ( double )img.width(); } } } if ( usePict || !fitsInCache ) { p->setOpacity( context.alpha() ); const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( mPath, size, mFillColor, mOutlineColor, mOutlineWidth, context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() ); if ( pct.width() > 1 ) { p->drawPicture( 0, 0, pct ); hwRatio = ( double )pct.height() / ( double )pct.width(); } } if ( context.selected() ) { QPen pen( context.selectionColor() ); double penWidth = context.outputLineWidth( 1.0 ); if ( penWidth > size / 20 ) { // keep the pen width from covering symbol penWidth = size / 20; } double penOffset = penWidth / 2; pen.setWidth( penWidth ); p->setPen( pen ); p->setBrush( Qt::NoBrush ); double wSize = size + penOffset; double hSize = size * hwRatio + penOffset; p->drawRect( QRectF( -wSize / 2.0, -hSize / 2.0, wSize, hSize ) ); } p->restore(); }