void QgsVectorFieldSymbolLayer::renderPoint( QPointF point, QgsSymbolRenderContext& context ) { if ( !mLineSymbol ) { return; } const QgsRenderContext& ctx = context.renderContext(); const QgsFeature* f = context.feature(); if ( !f ) { //preview QPolygonF line; line << QPointF( 0, 50 ); line << QPointF( 100, 50 ); mLineSymbol->renderPolyline( line, nullptr, context.renderContext() ); } double xComponent = 0; double yComponent = 0; double xVal = 0; if ( f && mXIndex != -1 ) { xVal = f->attribute( mXIndex ).toDouble(); } double yVal = 0; if ( f && mYIndex != -1 ) { yVal = f->attribute( mYIndex ).toDouble(); } switch ( mVectorFieldType ) { case Cartesian: xComponent = QgsSymbolLayerUtils::convertToPainterUnits( ctx, xVal, mDistanceUnit, mDistanceMapUnitScale ); yComponent = QgsSymbolLayerUtils::convertToPainterUnits( ctx, yVal, mDistanceUnit, mDistanceMapUnitScale ); break; case Polar: convertPolarToCartesian( xVal, yVal, xComponent, yComponent ); xComponent = QgsSymbolLayerUtils::convertToPainterUnits( ctx, xComponent, mDistanceUnit, mDistanceMapUnitScale ); yComponent = QgsSymbolLayerUtils::convertToPainterUnits( ctx, yComponent, mDistanceUnit, mDistanceMapUnitScale ); break; case Height: xComponent = 0; yComponent = QgsSymbolLayerUtils::convertToPainterUnits( ctx, yVal, mDistanceUnit, mDistanceMapUnitScale ); 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 QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext& 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( QgsSymbolLayer::EXPR_OFFSET ) ) { context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePoint( mOffset ) ); QPointF offset = QgsSymbolLayerUtils::decodePoint( evaluateDataDefinedProperty( QgsSymbolLayer::EXPR_OFFSET, context ).toString() ); offsetX = offset.x(); offsetY = offset.y(); } offsetX = QgsSymbolLayerUtils::convertToPainterUnits( context.renderContext(), offsetX, mOffsetUnit, mOffsetMapUnitScale ); offsetY = QgsSymbolLayerUtils::convertToPainterUnits( context.renderContext(), offsetY, mOffsetUnit, mOffsetMapUnitScale ); HorizontalAnchorPoint horizontalAnchorPoint = mHorizontalAnchorPoint; VerticalAnchorPoint verticalAnchorPoint = mVerticalAnchorPoint; if ( hasDataDefinedProperty( QgsSymbolLayer::EXPR_HORIZONTAL_ANCHOR_POINT ) ) { horizontalAnchorPoint = decodeHorizontalAnchorPoint( evaluateDataDefinedProperty( QgsSymbolLayer::EXPR_HORIZONTAL_ANCHOR_POINT , context ).toString() ); } if ( hasDataDefinedProperty( QgsSymbolLayer::EXPR_VERTICAL_ANCHOR_POINT ) ) { verticalAnchorPoint = decodeVerticalAnchorPoint( evaluateDataDefinedProperty( QgsSymbolLayer::EXPR_VERTICAL_ANCHOR_POINT, context ).toString() ); } //correct horizontal position according to anchor point if ( horizontalAnchorPoint == HCenter && verticalAnchorPoint == VCenter ) { return; } double anchorPointCorrectionX = QgsSymbolLayerUtils::convertToPainterUnits( context.renderContext(), width, widthUnit, widthMapUnitScale ) / 2.0; double anchorPointCorrectionY = QgsSymbolLayerUtils::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; } }
void QgsVectorFieldSymbolLayer::stopRender( QgsSymbolRenderContext& context ) { if ( mLineSymbol ) { mLineSymbol->stopRender( context.renderContext() ); } }
void QgsPointDisplacementRenderer::drawGrid( int gridSizeUnits, QgsSymbolRenderContext &context, QList<QPointF> pointSymbolPositions, int nSymbols ) { QPainter *p = context.renderContext().painter(); if ( nSymbols < 2 || !p ) //draw grid only if multiple features { return; } QPen gridPen( mCircleColor ); gridPen.setWidthF( context.outputLineWidth( mCircleWidth ) ); p->setPen( gridPen ); for ( int i = 0; i < pointSymbolPositions.size(); ++i ) { if ( i + 1 < pointSymbolPositions.size() && 0 != ( i + 1 ) % gridSizeUnits ) { QLineF gridLineRow( pointSymbolPositions[i], pointSymbolPositions[i + 1] ); p->drawLine( gridLineRow ); } if ( i + gridSizeUnits < pointSymbolPositions.size() ) { QLineF gridLineColumn( pointSymbolPositions[i], pointSymbolPositions[i + gridSizeUnits] ); p->drawLine( gridLineColumn ); } } }
void QgsVectorFieldSymbolLayer::drawPreviewIcon( QgsSymbolRenderContext& context, QSize size ) { if ( mLineSymbol ) { mLineSymbol->drawPreviewIcon( context.renderContext().painter(), size ); } }
void QgsFillSymbolLayer::_renderPolygon( QPainter* p, const QPolygonF& points, const QList<QPolygonF>* rings, QgsSymbolRenderContext& context ) { if ( !p ) { return; } // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #5 points). if ( points.size() <= 5 && ( context.renderContext().vectorSimplifyMethod().simplifyHints() & QgsVectorSimplifyMethod::AntialiasingSimplification ) && QgsAbstractGeometrySimplifier::isGeneralizableByDeviceBoundingBox( points, context.renderContext().vectorSimplifyMethod().threshold() ) && ( p->renderHints() & QPainter::Antialiasing ) ) { p->setRenderHint( QPainter::Antialiasing, false ); p->drawRect( points.boundingRect() ); p->setRenderHint( QPainter::Antialiasing, true ); return; } // polygons outlines are sometimes rendered wrongly with drawPolygon, when // clipped (see #13343), so use drawPath instead. if ( !rings && p->pen().style() == Qt::NoPen ) { // simple polygon without holes p->drawPolygon( points ); } else { // polygon with holes must be drawn using painter path QPainterPath path; QPolygonF outerRing = points; path.addPolygon( outerRing ); if ( rings ) { QList<QPolygonF>::const_iterator it = rings->constBegin(); for ( ; it != rings->constEnd(); ++it ) { QPolygonF ring = *it; path.addPolygon( ring ); } } p->drawPath( path ); } }
void QgsEllipseSymbolLayer::calculateOffsetAndRotation( QgsSymbolRenderContext &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 ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle ) ) { context.setOriginalValueVariable( angle ); angle = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyAngle, context.renderContext().expressionContext(), 0 ) + mLineAngle; usingDataDefinedRotation = ok; } hasDataDefinedRotation = context.renderHints() & QgsSymbol::DynamicRotation || 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->geometry(); if ( !g.isNull() && g.type() == QgsWkbTypes::PointGeometry ) { const QgsMapToPixel &m2p = context.renderContext().mapToPixel(); angle += m2p.mapRotation(); } } } if ( angle ) offset = _rotatedOffset( offset, angle ); }
QRectF QgsEllipseSymbolLayer::bounds( QPointF point, QgsSymbolRenderContext &context ) { QSizeF size = calculateSize( context ); bool hasDataDefinedRotation = false; QPointF offset; double angle = 0; calculateOffsetAndRotation( context, size.width(), size.height(), hasDataDefinedRotation, offset, angle ); 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; if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeWidth ) ) { context.setOriginalValueVariable( mStrokeWidth ); QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext() ); if ( exprVal.isValid() ) { bool ok; double strokeWidth = exprVal.toDouble( &ok ); if ( ok ) { penWidth = context.renderContext().convertToPainterUnits( strokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ); } } } if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeStyle ) ) { context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePenStyle( mStrokeStyle ) ); QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyStrokeStyle, context.renderContext().expressionContext() ); if ( exprVal.isValid() && exprVal.toString() == QLatin1String( "no" ) ) { penWidth = 0.0; } } //antialiasing, add 1 pixel penWidth += 1; 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; }
void QgsSymbolLayer::prepareExpressions( const QgsSymbolRenderContext &context ) { mDataDefinedProperties.prepare( context.renderContext().expressionContext() ); if ( !context.fields().isEmpty() ) { //QgsFields is implicitly shared, so it's cheap to make a copy mFields = context.fields(); } }
void QgsEllipseSymbolLayer::startRender( QgsSymbolRenderContext &context ) { QgsMarkerSymbolLayer::startRender( context ); // get anchor point expressions if ( !context.feature() || !dataDefinedProperties().hasActiveProperties() ) { preparePath( mSymbolName, context ); } mPen.setColor( mStrokeColor ); mPen.setStyle( mStrokeStyle ); mPen.setJoinStyle( mPenJoinStyle ); mPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) ); mBrush.setColor( mColor ); }
void QgsPointDisplacementRenderer::drawCircle( double radiusPainterUnits, QgsSymbolRenderContext &context, QPointF centerPoint, int nSymbols ) { QPainter *p = context.renderContext().painter(); if ( nSymbols < 2 || !p ) //draw circle only if multiple features { return; } //draw Circle QPen circlePen( mCircleColor ); circlePen.setWidthF( context.outputLineWidth( mCircleWidth ) ); p->setPen( circlePen ); p->drawArc( QRectF( centerPoint.x() - radiusPainterUnits, centerPoint.y() - radiusPainterUnits, 2 * radiusPainterUnits, 2 * radiusPainterUnits ), 0, 5760 ); }
QSizeF QgsEllipseSymbolLayer::calculateSize( QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight ) { double width = 0; if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) ) //1. priority: data defined setting on symbol layer le { context.setOriginalValueVariable( mSymbolWidth ); width = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyWidth, context.renderContext().expressionContext(), mSymbolWidth ); } else //2. priority: global width setting { width = mSymbolWidth; } if ( scaledWidth ) { *scaledWidth = width; } width = context.renderContext().convertToPainterUnits( width, mSymbolWidthUnit, mSymbolHeightMapUnitScale ); double height = 0; if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) ) //1. priority: data defined setting on symbol layer level { context.setOriginalValueVariable( mSymbolHeight ); height = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyHeight, context.renderContext().expressionContext(), mSymbolHeight ); } else //2. priority: global height setting { height = mSymbolHeight; } if ( scaledHeight ) { *scaledHeight = height; } height = context.renderContext().convertToPainterUnits( height, mSymbolHeightUnit, mSymbolHeightMapUnitScale ); return QSizeF( width, height ); }
void QgsMarkerSymbolLayer::drawPreviewIcon( QgsSymbolRenderContext &context, QSize size ) { startRender( context ); QgsPaintEffect *effect = paintEffect(); if ( effect && effect->enabled() ) { QgsEffectPainter p( context.renderContext(), effect ); renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context ); } else { renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context ); } stopRender( context ); }
void QgsFillSymbolLayer::drawPreviewIcon( QgsSymbolRenderContext &context, QSize size ) { QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width(), size.height() ) ); startRender( context ); QgsPaintEffect *effect = paintEffect(); if ( effect && effect->enabled() ) { QgsEffectPainter p( context.renderContext(), effect ); renderPolygon( poly, nullptr, context ); } else { renderPolygon( poly, nullptr, context ); } stopRender( context ); }
void QgsSymbolLayer::prepareExpressions( const QgsSymbolRenderContext& context ) { QMap< QString, QgsDataDefined* >::const_iterator it = mDataDefinedProperties.constBegin(); for ( ; it != mDataDefinedProperties.constEnd(); ++it ) { if ( it.value() ) { it.value()->prepareExpression( context.renderContext().expressionContext() ); } } if ( !context.fields().isEmpty() ) { //QgsFields is implicitly shared, so it's cheap to make a copy mFields = context.fields(); } }
void QgsVectorFieldSymbolLayer::startRender( QgsSymbolRenderContext& context ) { if ( mLineSymbol ) { mLineSymbol->startRender( context.renderContext(), context.fields() ); } QgsFields fields = context.fields(); if ( !fields.isEmpty() ) { mXIndex = fields.lookupField( mXAttribute ); mYIndex = fields.lookupField( mYAttribute ); } else { mXIndex = -1; mYIndex = -1; } }
void QgsLineSymbolLayer::drawPreviewIcon( QgsSymbolRenderContext &context, QSize size ) { QPolygonF points; // we're adding 0.5 to get rid of blurred preview: // drawing antialiased lines of width 1 at (x,0)-(x,100) creates 2px line points << QPointF( 0, int( size.height() / 2 ) + 0.5 ) << QPointF( size.width(), int( size.height() / 2 ) + 0.5 ); startRender( context ); QgsPaintEffect *effect = paintEffect(); if ( effect && effect->enabled() ) { QgsEffectPainter p( context.renderContext(), effect ); renderPolyline( points, context ); } else { renderPolyline( points, context ); } stopRender( context ); }
QVariant QgsSymbolLayer::evaluateDataDefinedProperty( const QString& property, const QgsSymbolRenderContext& context, const QVariant& defaultVal, bool* ok ) const { if ( ok ) *ok = false; QgsDataDefined* dd = getDataDefinedProperty( property ); if ( !dd || !dd->isActive() ) return defaultVal; if ( dd->useExpression() ) { if ( dd->expression() ) { QVariant result = dd->expression()->evaluate( &context.renderContext().expressionContext() ); if ( result.isValid() ) { if ( ok ) *ok = true; return result; } else return defaultVal; } else { return defaultVal; } } else if ( context.feature() && !dd->field().isEmpty() && !mFields.isEmpty() ) { int attributeIndex = mFields.lookupField( dd->field() ); if ( attributeIndex >= 0 ) { if ( ok ) *ok = true; return context.feature()->attribute( attributeIndex ); } } return defaultVal; }
void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRenderContext &symbolContext, QPointF centerPoint, int nPosition, double symbolDiagonal, QList<QPointF> &symbolPositions, QList<QPointF> &labelShifts, double &circleRadius, double &gridRadius, int &gridSize ) const { symbolPositions.clear(); labelShifts.clear(); if ( nPosition < 1 ) { return; } else if ( nPosition == 1 ) //If there is only one feature, draw it exactly at the center position { symbolPositions.append( centerPoint ); labelShifts.append( QPointF( symbolDiagonal / 2.0, -symbolDiagonal / 2.0 ) ); return; } double circleAdditionPainterUnits = symbolContext.outputLineWidth( mCircleRadiusAddition ); switch ( mPlacement ) { case Ring: { double minDiameterToFitSymbols = nPosition * symbolDiagonal / ( 2.0 * M_PI ); double radius = std::max( symbolDiagonal / 2, minDiameterToFitSymbols ) + circleAdditionPainterUnits; double fullPerimeter = 2 * M_PI; double angleStep = fullPerimeter / nPosition; for ( double currentAngle = 0.0; currentAngle < fullPerimeter; currentAngle += angleStep ) { double sinusCurrentAngle = std::sin( currentAngle ); double cosinusCurrentAngle = std::cos( currentAngle ); QPointF positionShift( radius * sinusCurrentAngle, radius * cosinusCurrentAngle ); QPointF labelShift( ( radius + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radius + symbolDiagonal / 2 ) * cosinusCurrentAngle ); symbolPositions.append( centerPoint + positionShift ); labelShifts.append( labelShift ); } circleRadius = radius; break; } case ConcentricRings: { double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2; int pointsRemaining = nPosition; int ringNumber = 1; double firstRingRadius = centerDiagonal / 2.0 + symbolDiagonal / 2.0; while ( pointsRemaining > 0 ) { double radiusCurrentRing = std::max( firstRingRadius + ( ringNumber - 1 ) * symbolDiagonal + ringNumber * circleAdditionPainterUnits, 0.0 ); int maxPointsCurrentRing = std::max( std::floor( 2 * M_PI * radiusCurrentRing / symbolDiagonal ), 1.0 ); int actualPointsCurrentRing = std::min( maxPointsCurrentRing, pointsRemaining ); double angleStep = 2 * M_PI / actualPointsCurrentRing; double currentAngle = 0.0; for ( int i = 0; i < actualPointsCurrentRing; ++i ) { double sinusCurrentAngle = std::sin( currentAngle ); double cosinusCurrentAngle = std::cos( currentAngle ); QPointF positionShift( radiusCurrentRing * sinusCurrentAngle, radiusCurrentRing * cosinusCurrentAngle ); QPointF labelShift( ( radiusCurrentRing + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radiusCurrentRing + symbolDiagonal / 2 ) * cosinusCurrentAngle ); symbolPositions.append( centerPoint + positionShift ); labelShifts.append( labelShift ); currentAngle += angleStep; } pointsRemaining -= actualPointsCurrentRing; ringNumber++; circleRadius = radiusCurrentRing; } break; } case Grid: { double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2; int pointsRemaining = nPosition; gridSize = std::ceil( std::sqrt( pointsRemaining ) ); if ( pointsRemaining - std::pow( gridSize - 1, 2 ) < gridSize ) gridSize -= 1; double originalPointRadius = ( ( centerDiagonal / 2.0 + symbolDiagonal / 2.0 ) + symbolDiagonal ) / 2; double userPointRadius = originalPointRadius + circleAdditionPainterUnits; int yIndex = 0; while ( pointsRemaining > 0 ) { for ( int xIndex = 0; xIndex < gridSize && pointsRemaining > 0; ++xIndex ) { QPointF positionShift( userPointRadius * xIndex, userPointRadius * yIndex ); QPointF labelShift( ( userPointRadius + symbolDiagonal / 2 ) * xIndex, ( userPointRadius + symbolDiagonal / 2 ) * yIndex ); symbolPositions.append( centerPoint + positionShift ); labelShifts.append( labelShift ); pointsRemaining--; } yIndex++; } centralizeGrid( symbolPositions, userPointRadius, gridSize ); centralizeGrid( labelShifts, userPointRadius, gridSize ); gridRadius = userPointRadius; break; } } }
void QgsGeometryGeneratorSymbolLayer::startRender( QgsSymbolRenderContext& context ) { mExpression->prepare( &context.renderContext().expressionContext() ); subSymbol()->startRender( context.renderContext() ); }
void QgsGeometryGeneratorSymbolLayer::drawPreviewIcon( QgsSymbolRenderContext& context, QSize size ) { if ( mSymbol ) mSymbol->drawPreviewIcon( context.renderContext().painter(), size ); }
void QgsGeometryGeneratorSymbolLayer::stopRender( QgsSymbolRenderContext& context ) { if ( mSymbol ) mSymbol->stopRender( context.renderContext() ); }
bool QgsEllipseSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const { //width double symbolWidth = mSymbolWidth; if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) ) //1. priority: data defined setting on symbol layer le { context.setOriginalValueVariable( mSymbolWidth ); symbolWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyWidth, context.renderContext().expressionContext(), mSymbolWidth ); } if ( mSymbolWidthUnit == QgsUnitTypes::RenderMillimeters ) { symbolWidth *= mmMapUnitScaleFactor; } //height double symbolHeight = mSymbolHeight; if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) ) //1. priority: data defined setting on symbol layer level { context.setOriginalValueVariable( mSymbolHeight ); symbolWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyHeight, context.renderContext().expressionContext(), mSymbolHeight ); } if ( mSymbolHeightUnit == QgsUnitTypes::RenderMillimeters ) { symbolHeight *= mmMapUnitScaleFactor; } //stroke width double strokeWidth = mStrokeWidth; if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeWidth ) ) { context.setOriginalValueVariable( mStrokeWidth ); strokeWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext(), mStrokeWidth ); } if ( mStrokeWidthUnit == QgsUnitTypes::RenderMillimeters ) { strokeWidth *= strokeWidth; } //fill color QColor fc = mColor; if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFillColor ) ) { context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mColor ) ); fc = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyFillColor, context.renderContext().expressionContext(), mColor ); } //stroke color QColor oc = mStrokeColor; if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeColor ) ) { context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mStrokeColor ) ); oc = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyStrokeColor, context.renderContext().expressionContext(), mStrokeColor ); } //symbol name QString symbolName = mSymbolName; if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyName ) ) { context.setOriginalValueVariable( mSymbolName ); symbolName = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyName, context.renderContext().expressionContext(), mSymbolName ); } //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 ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle ) ) { context.setOriginalValueVariable( mAngle ); rotation = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyAngle, context.renderContext().expressionContext(), mAngle ) + 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 == QLatin1String( "circle" ) ) { if ( qgsDoubleNear( halfWidth, halfHeight ) ) { QgsPoint pt( t.map( QPointF( 0, 0 ) ) ); e.writeFilledCircle( layerName, oc, pt, halfWidth ); } else { QgsPointSequence line; double stepsize = 2 * M_PI / 40; for ( int i = 0; i < 39; ++i ) { double angle = stepsize * i; double x = halfWidth * std::cos( angle ); double y = halfHeight * std::sin( angle ); line << QgsPoint( t.map( QPointF( x, y ) ) ); } //close ellipse with first point line << line.at( 0 ); if ( mBrush.style() != Qt::NoBrush ) e.writePolygon( QgsRingSequence() << line, layerName, QStringLiteral( "SOLID" ), fc ); if ( mPen.style() != Qt::NoPen ) e.writePolyline( line, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth ); } } else if ( symbolName == QLatin1String( "rectangle" ) ) { QgsPointSequence p; p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) ) << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) ) << QgsPoint( t.map( QPointF( halfWidth, halfHeight ) ) ) << QgsPoint( t.map( QPointF( -halfWidth, halfHeight ) ) ); p << p[0]; if ( mBrush.style() != Qt::NoBrush ) e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc ); if ( mPen.style() != Qt::NoPen ) e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth ); return true; } else if ( symbolName == QLatin1String( "cross" ) && mPen.style() != Qt::NoPen ) { e.writePolyline( QgsPointSequence() << QgsPoint( t.map( QPointF( -halfWidth, 0 ) ) ) << QgsPoint( t.map( QPointF( halfWidth, 0 ) ) ), layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth ); e.writePolyline( QgsPointSequence() << QgsPoint( t.map( QPointF( 0, halfHeight ) ) ) << QgsPoint( t.map( QPointF( 0, -halfHeight ) ) ), layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth ); return true; } else if ( symbolName == QLatin1String( "triangle" ) ) { QgsPointSequence p; p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) ) << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) ) << QgsPoint( t.map( QPointF( 0, halfHeight ) ) ); p << p[0]; if ( mBrush.style() != Qt::NoBrush ) e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc ); if ( mPen.style() != Qt::NoPen ) e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth ); return true; } return false; //soon... }
double QgsLineSymbolLayer::dxfWidth( const QgsDxfExport &e, QgsSymbolRenderContext &context ) const { Q_UNUSED( context ); return width() * e.mapUnitScaleFactor( e.symbologyScale(), widthUnit(), e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() ); }
void QgsEllipseSymbolLayer::renderPoint( QPointF point, QgsSymbolRenderContext &context ) { double scaledWidth = mSymbolWidth; double scaledHeight = mSymbolHeight; if ( mDataDefinedProperties.hasActiveProperties() ) { bool ok; context.setOriginalValueVariable( mStrokeWidth ); QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext() ); if ( exprVal.isValid() ) { double width = exprVal.toDouble( &ok ); if ( ok ) { width = context.renderContext().convertToPainterUnits( width, mStrokeWidthUnit, mStrokeWidthMapUnitScale ); mPen.setWidthF( width ); } } context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePenStyle( mStrokeStyle ) ); exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyStrokeStyle, context.renderContext().expressionContext() ); if ( exprVal.isValid() ) { mPen.setStyle( QgsSymbolLayerUtils::decodePenStyle( exprVal.toString() ) ); } context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle ) ); exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyJoinStyle, context.renderContext().expressionContext() ); if ( exprVal.isValid() ) { mPen.setJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( exprVal.toString() ) ); } context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mColor ) ); mBrush.setColor( mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyFillColor, context.renderContext().expressionContext(), mColor ) ); context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mStrokeColor ) ); mPen.setColor( mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyStrokeColor, context.renderContext().expressionContext(), mStrokeColor ) ); if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) || mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) || mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyName ) ) { QString symbolName = mSymbolName; context.setOriginalValueVariable( mSymbolName ); exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyName, context.renderContext().expressionContext() ); if ( exprVal.isValid() ) { symbolName = exprVal.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 ) ); }
void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &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 ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyOffset ) ) { context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePoint( mOffset ) ); QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyOffset, context.renderContext().expressionContext() ); if ( exprVal.isValid() ) { QPointF offset = QgsSymbolLayerUtils::decodePoint( exprVal.toString() ); offsetX = offset.x(); offsetY = offset.y(); } } offsetX = context.renderContext().convertToPainterUnits( offsetX, mOffsetUnit, mOffsetMapUnitScale ); offsetY = context.renderContext().convertToPainterUnits( offsetY, mOffsetUnit, mOffsetMapUnitScale ); HorizontalAnchorPoint horizontalAnchorPoint = mHorizontalAnchorPoint; VerticalAnchorPoint verticalAnchorPoint = mVerticalAnchorPoint; if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHorizontalAnchor ) ) { QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyHorizontalAnchor, context.renderContext().expressionContext() ); if ( exprVal.isValid() ) { horizontalAnchorPoint = decodeHorizontalAnchorPoint( exprVal.toString() ); } } if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyVerticalAnchor ) ) { QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyVerticalAnchor, context.renderContext().expressionContext() ); if ( exprVal.isValid() ) { verticalAnchorPoint = decodeVerticalAnchorPoint( exprVal.toString() ); } } //correct horizontal position according to anchor point if ( horizontalAnchorPoint == HCenter && verticalAnchorPoint == VCenter ) { return; } double anchorPointCorrectionX = context.renderContext().convertToPainterUnits( width, widthUnit, widthMapUnitScale ) / 2.0; double anchorPointCorrectionY = context.renderContext().convertToPainterUnits( 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; } }
void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRenderContext& symbolContext, QPointF centerPoint, int nPosition, double symbolDiagonal, QList<QPointF>& symbolPositions, QList<QPointF>& labelShifts, double& circleRadius ) const { symbolPositions.clear(); labelShifts.clear(); if ( nPosition < 1 ) { return; } else if ( nPosition == 1 ) //If there is only one feature, draw it exactly at the center position { symbolPositions.append( centerPoint ); labelShifts.append( QPointF( symbolDiagonal / 2.0, -symbolDiagonal / 2.0 ) ); return; } double circleAdditionPainterUnits = symbolContext.outputLineWidth( mCircleRadiusAddition ); switch ( mPlacement ) { case Ring: { double minDiameterToFitSymbols = nPosition * symbolDiagonal / ( 2.0 * M_PI ); double radius = qMax( symbolDiagonal / 2, minDiameterToFitSymbols ) + circleAdditionPainterUnits; double fullPerimeter = 2 * M_PI; double angleStep = fullPerimeter / nPosition; for ( double currentAngle = 0.0; currentAngle < fullPerimeter; currentAngle += angleStep ) { double sinusCurrentAngle = sin( currentAngle ); double cosinusCurrentAngle = cos( currentAngle ); QPointF positionShift( radius * sinusCurrentAngle, radius * cosinusCurrentAngle ); QPointF labelShift(( radius + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radius + symbolDiagonal / 2 ) * cosinusCurrentAngle ); symbolPositions.append( centerPoint + positionShift ); labelShifts.append( labelShift ); } circleRadius = radius; break; } case ConcentricRings: { double centerDiagonal = symbolContext.renderContext().convertToPainterUnits( M_SQRT2 * mCenterSymbol->size(), mCenterSymbol->sizeUnit(), mCenterSymbol->sizeMapUnitScale() ); int pointsRemaining = nPosition; int ringNumber = 1; double firstRingRadius = centerDiagonal / 2.0 + symbolDiagonal / 2.0; while ( pointsRemaining > 0 ) { double radiusCurrentRing = qMax( firstRingRadius + ( ringNumber - 1 ) * symbolDiagonal + ringNumber * circleAdditionPainterUnits, 0.0 ); int maxPointsCurrentRing = qMax( floor( 2 * M_PI * radiusCurrentRing / symbolDiagonal ), 1.0 ); int actualPointsCurrentRing = qMin( maxPointsCurrentRing, pointsRemaining ); double angleStep = 2 * M_PI / actualPointsCurrentRing; double currentAngle = 0.0; for ( int i = 0; i < actualPointsCurrentRing; ++i ) { double sinusCurrentAngle = sin( currentAngle ); double cosinusCurrentAngle = cos( currentAngle ); QPointF positionShift( radiusCurrentRing * sinusCurrentAngle, radiusCurrentRing * cosinusCurrentAngle ); QPointF labelShift(( radiusCurrentRing + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radiusCurrentRing + symbolDiagonal / 2 ) * cosinusCurrentAngle ); symbolPositions.append( centerPoint + positionShift ); labelShifts.append( labelShift ); currentAngle += angleStep; } pointsRemaining -= actualPointsCurrentRing; ringNumber++; circleRadius = radiusCurrentRing; } break; } } }