QSizeF QgsTextDiagram::diagramSize( const QgsFeature& feature, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is ) { QgsExpressionContext expressionContext = c.expressionContext(); expressionContext.setFeature( feature ); if ( feature.fields() ) expressionContext.setFields( *feature.fields() ); QVariant attrVal; if ( is.classificationAttributeIsExpression ) { QgsExpression* expression = getExpression( is.classificationAttributeExpression, expressionContext ); attrVal = expression->evaluate( &expressionContext ); } else { attrVal = feature.attributes().at( is.classificationAttribute ); } bool ok = false; double val = attrVal.toDouble( &ok ); if ( !ok ) { return QSizeF(); //zero size if attribute is missing } return sizeForValue( val, s, is ); }
QSizeF QgsHistogramDiagram::diagramSize( const QgsFeature& feature, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is ) { QSizeF size; if ( feature.attributes().isEmpty() ) { return size; //zero size if no attributes } if ( qgsDoubleNear( is.upperValue, is.lowerValue ) ) return size; // invalid value range => zero size double maxValue = 0; QgsExpressionContext expressionContext = c.expressionContext(); expressionContext.setFeature( feature ); if ( !feature.fields().isEmpty() ) expressionContext.setFields( feature.fields() ); Q_FOREACH ( const QString& cat, s.categoryAttributes ) { QgsExpression* expression = getExpression( cat, expressionContext ); maxValue = qMax( expression->evaluate( &expressionContext ).toDouble(), maxValue ); } // Scale, if extension is smaller than the specified minimum if ( maxValue < s.minimumSize ) { maxValue = s.minimumSize; } switch ( s.diagramOrientation ) { case QgsDiagramSettings::Up: case QgsDiagramSettings::Down: mScaleFactor = (( is.upperSize.width() - is.lowerSize.height() ) / ( is.upperValue - is.lowerValue ) ); size.scale( s.barWidth * s.categoryAttributes.size(), maxValue * mScaleFactor, Qt::IgnoreAspectRatio ); break; case QgsDiagramSettings::Right: case QgsDiagramSettings::Left: mScaleFactor = (( is.upperSize.width() - is.lowerSize.width() ) / ( is.upperValue - is.lowerValue ) ); size.scale( maxValue * mScaleFactor, s.barWidth * s.categoryAttributes.size(), Qt::IgnoreAspectRatio ); break; } return size; }
void QgsEditorWidgetWrapper::updateConstraint( const QgsFeature &ft ) { bool toEmit( false ); QString errStr( tr( "predicate is True" ) ); QString expression = layer()->editFormConfig().constraintExpression( mFieldIdx ); QString description; QVariant value = ft.attribute( mFieldIdx ); if ( ! expression.isEmpty() ) { description = layer()->editFormConfig().constraintDescription( mFieldIdx ); QgsExpressionContext context = layer()->createExpressionContext(); context.setFeature( ft ); QgsExpression expr( expression ); mValidConstraint = expr.evaluate( &context ).toBool(); if ( expr.hasParserError() ) errStr = expr.parserErrorString(); else if ( expr.hasEvalError() ) errStr = expr.evalErrorString(); else if ( ! mValidConstraint ) errStr = tr( "predicate is False" ); toEmit = true; } else mValidConstraint = true; if ( layer()->editFormConfig().notNull( mFieldIdx ) ) { if ( !expression.isEmpty() ) { QString fieldName = ft.fields().field( mFieldIdx ).name(); expression = "( " + expression + " ) AND ( " + fieldName + " IS NOT NULL)"; description = "( " + description + " ) AND NotNull"; } else { description = QStringLiteral( "NotNull" ); expression = QStringLiteral( "NotNull" ); } mValidConstraint = mValidConstraint && !value.isNull(); if ( value.isNull() ) errStr = tr( "predicate is False" ); toEmit = true; } if ( toEmit ) { updateConstraintWidgetStatus( mValidConstraint ); emit constraintStatusChanged( expression, description, errStr, mValidConstraint ); } }
void QgsActionManager::doAction( const QUuid& actionId, const QgsFeature& feature, int defaultValueIndex ) { QgsExpressionContext context = createExpressionContext(); QgsExpressionContextScope* actionScope = new QgsExpressionContextScope(); actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "field_index" ), defaultValueIndex, true ) ); if ( defaultValueIndex >= 0 && defaultValueIndex < feature.fields().size() ) actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "field_name" ), feature.fields().at( defaultValueIndex ).name(), true ) ); actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "field_value" ), feature.attribute( defaultValueIndex ), true ) ); context << actionScope; doAction( actionId, feature, context ); }
QSizeF QgsTextDiagram::diagramSize( const QgsFeature& feature, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is ) { Q_UNUSED( c ); QVariant attrVal; if ( is.classificationAttributeIsExpression ) { QgsExpression* expression = getExpression( is.classificationAttributeExpression, feature.fields() ); attrVal = expression->evaluate( feature ); } else { attrVal = feature.attributes()[is.classificationAttribute]; } if ( !attrVal.isValid() ) { return QSizeF(); //zero size if attribute is missing } double scaledValue = attrVal.toDouble(); double scaledLowerValue = is.lowerValue; double scaledUpperValue = is.upperValue; double scaledLowerSizeWidth = is.lowerSize.width(); double scaledLowerSizeHeight = is.lowerSize.height(); double scaledUpperSizeWidth = is.upperSize.width(); double scaledUpperSizeHeight = is.upperSize.height(); // interpolate the squared value if scale by area if ( s.scaleByArea ) { scaledValue = sqrt( scaledValue ); scaledLowerValue = sqrt( scaledLowerValue ); scaledUpperValue = sqrt( scaledUpperValue ); scaledLowerSizeWidth = sqrt( scaledLowerSizeWidth ); scaledLowerSizeHeight = sqrt( scaledLowerSizeHeight ); scaledUpperSizeWidth = sqrt( scaledUpperSizeWidth ); scaledUpperSizeHeight = sqrt( scaledUpperSizeHeight ); } //interpolate size double scaledRatio = ( scaledValue - scaledLowerValue ) / ( scaledUpperValue - scaledLowerValue ); QSizeF size = QSizeF( is.upperSize.width() * scaledRatio + is.lowerSize.width() * ( 1 - scaledRatio ), is.upperSize.height() * scaledRatio + is.lowerSize.height() * ( 1 - scaledRatio ) ); // Scale, if extension is smaller than the specified minimum if ( size.width() <= s.minimumSize && size.height() <= s.minimumSize ) { size.scale( s.minimumSize, s.minimumSize, Qt::KeepAspectRatio ); } return size; }
void QgsHistogramDiagram::renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, QPointF position ) { QPainter* p = c.painter(); if ( !p ) { return; } QList<double> values; double maxValue = 0; QgsExpressionContext expressionContext = c.expressionContext(); expressionContext.setFeature( feature ); if ( !feature.fields().isEmpty() ) expressionContext.setFields( feature.fields() ); Q_FOREACH ( const QString& cat, s.categoryAttributes ) { QgsExpression* expression = getExpression( cat, expressionContext ); double currentVal = expression->evaluate( &expressionContext ).toDouble(); values.push_back( currentVal ); maxValue = qMax( currentVal, maxValue ); } double scaledMaxVal = sizePainterUnits( maxValue * mScaleFactor, s, c ); double currentOffset = 0; double scaledWidth = sizePainterUnits( s.barWidth, s, c ); double baseX = position.x(); double baseY = position.y(); mPen.setColor( s.penColor ); setPenWidth( mPen, s, c ); p->setPen( mPen ); QList<double>::const_iterator valIt = values.constBegin(); QList< QColor >::const_iterator colIt = s.categoryColors.constBegin(); for ( ; valIt != values.constEnd(); ++valIt, ++colIt ) { double length = sizePainterUnits( *valIt * mScaleFactor, s, c ); mCategoryBrush.setColor( *colIt ); p->setBrush( mCategoryBrush ); switch ( s.diagramOrientation ) { case QgsDiagramSettings::Up: p->drawRect( baseX + currentOffset, baseY, scaledWidth, length * -1 ); break; case QgsDiagramSettings::Down: p->drawRect( baseX + currentOffset, baseY - scaledMaxVal, scaledWidth, length ); break; case QgsDiagramSettings::Right: p->drawRect( baseX, baseY - currentOffset, length, scaledWidth * -1 ); break; case QgsDiagramSettings::Left: p->drawRect( baseX + scaledMaxVal, baseY - currentOffset, 0 - length, scaledWidth * -1 ); break; } currentOffset += scaledWidth; } }
void QgsTextDiagram::renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, QPointF position ) { QPainter* p = c.painter(); if ( !p ) { return; } //convert from mm / map units to painter units QSizeF spu = sizePainterUnits( s.size, s, c ); double w = spu.width(); double h = spu.height(); double baseX = position.x(); double baseY = position.y() - h; QVector<QPointF> textPositions; //midpoints for text placement int nCategories = s.categoryAttributes.size(); for ( int i = 0; i < nCategories; ++i ) { if ( mOrientation == Horizontal ) { textPositions.push_back( QPointF( baseX + ( w / nCategories ) * i + w / nCategories / 2.0, baseY + h / 2.0 ) ); } else //vertical { textPositions.push_back( QPointF( baseX + w / 2.0, baseY + h / nCategories * i + w / nCategories / 2.0 ) ); } } mPen.setColor( s.penColor ); setPenWidth( mPen, s, c ); p->setPen( mPen ); mBrush.setColor( s.backgroundColor ); p->setBrush( mBrush ); //draw shapes and separator lines first if ( mShape == Circle ) { p->drawEllipse( baseX, baseY, w, h ); //draw separator lines QList<QPointF> intersect; //intersections between shape and separation lines QPointF center( baseX + w / 2.0, baseY + h / 2.0 ); double r1 = w / 2.0; double r2 = h / 2.0; for ( int i = 1; i < nCategories; ++i ) { if ( mOrientation == Horizontal ) { lineEllipseIntersection( QPointF( baseX + w / nCategories * i, baseY ), QPointF( baseX + w / nCategories * i, baseY + h ), center, r1, r2, intersect ); } else //vertical { lineEllipseIntersection( QPointF( baseX, baseY + h / nCategories * i ), QPointF( baseX + w, baseY + h / nCategories * i ), center, r1, r2, intersect ); } if ( intersect.size() > 1 ) { p->drawLine( intersect.at( 0 ), intersect.at( 1 ) ); } } } else if ( mShape == Rectangle ) { p->drawRect( QRectF( baseX, baseY, w, h ) ); for ( int i = 1; i < nCategories; ++i ) { if ( mOrientation == Horizontal ) { p->drawLine( QPointF( baseX + w / nCategories * i, baseY ), QPointF( baseX + w / nCategories * i, baseY + h ) ); } else { p->drawLine( QPointF( baseX, baseY + h / nCategories * i ), QPointF( baseX + w, baseY + h / nCategories * i ) ); } } } else //triangle { QPolygonF triangle; triangle << QPointF( baseX, baseY + h ) << QPointF( baseX + w, baseY + h ) << QPointF( baseX + w / 2.0, baseY ); p->drawPolygon( triangle ); QLineF triangleEdgeLeft( baseX + w / 2.0, baseY, baseX, baseY + h ); QLineF triangleEdgeRight( baseX + w, baseY + h, baseX + w / 2.0, baseY ); QPointF intersectionPoint1, intersectionPoint2; for ( int i = 1; i < nCategories; ++i ) { if ( mOrientation == Horizontal ) { QLineF verticalLine( baseX + w / nCategories * i, baseY + h, baseX + w / nCategories * i, baseY ); if ( baseX + w / nCategories * i < baseX + w / 2.0 ) { verticalLine.intersect( triangleEdgeLeft, &intersectionPoint1 ); } else { verticalLine.intersect( triangleEdgeRight, &intersectionPoint1 ); } p->drawLine( QPointF( baseX + w / nCategories * i, baseY + h ), intersectionPoint1 ); } else //vertical { QLineF horizontalLine( baseX, baseY + h / nCategories * i, baseX + w, baseY + h / nCategories * i ); horizontalLine.intersect( triangleEdgeLeft, &intersectionPoint1 ); horizontalLine.intersect( triangleEdgeRight, &intersectionPoint2 ); p->drawLine( intersectionPoint1, intersectionPoint2 ); } } } //draw text QFont sFont = scaledFont( s, c ); QFontMetricsF fontMetrics( sFont ); p->setFont( sFont ); QgsExpressionContext expressionContext = c.expressionContext(); expressionContext.setFeature( feature ); if ( feature.fields() ) expressionContext.setFields( *feature.fields() ); for ( int i = 0; i < textPositions.size(); ++i ) { QgsExpression* expression = getExpression( s.categoryAttributes.at( i ), expressionContext ); QString val = expression->evaluate( &expressionContext ).toString(); //find out dimesions double textWidth = fontMetrics.width( val ); double textHeight = fontMetrics.height(); mPen.setColor( s.categoryColors.at( i ) ); p->setPen( mPen ); QPointF position = textPositions.at( i ); // Calculate vertical placement double xOffset = 0; switch ( s.labelPlacementMethod ) { case QgsDiagramSettings::Height: xOffset = textHeight / 2.0; break; case QgsDiagramSettings::XHeight: xOffset = fontMetrics.xHeight(); break; } p->drawText( QPointF( position.x() - textWidth / 2.0, position.y() + xOffset ), val ); } }
void QgsPieDiagram::renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position ) { QPainter* p = c.painter(); if ( !p ) { return; } //get sum of values QList<double> values; double currentVal = 0; double valSum = 0; int valCount = 0; QList<QString>::const_iterator catIt = s.categoryAttributes.constBegin(); for ( ; catIt != s.categoryAttributes.constEnd(); ++catIt ) { QgsExpression* expression = getExpression( *catIt, feature.fields() ); currentVal = expression->evaluate( feature ).toDouble(); values.push_back( currentVal ); valSum += currentVal; if ( currentVal ) valCount++; } //draw the slices double totalAngle = 0; double currentAngle; //convert from mm / map units to painter units QSizeF spu = sizePainterUnits( s.size, s, c ); double w = spu.width(); double h = spu.height(); double baseX = position.x(); double baseY = position.y() - h; mPen.setColor( s.penColor ); setPenWidth( mPen, s, c ); p->setPen( mPen ); // there are some values > 0 available if ( valSum > 0 ) { QList<double>::const_iterator valIt = values.constBegin(); QList< QColor >::const_iterator colIt = s.categoryColors.constBegin(); for ( ; valIt != values.constEnd(); ++valIt, ++colIt ) { if ( *valIt ) { currentAngle = *valIt / valSum * 360 * 16; mCategoryBrush.setColor( *colIt ); p->setBrush( mCategoryBrush ); // if only 1 value is > 0, draw a circle if ( valCount == 1 ) { p->drawEllipse( baseX, baseY, w, h ); } else { p->drawPie( baseX, baseY, w, h, totalAngle + s.angleOffset, currentAngle ); } totalAngle += currentAngle; } } } else // valSum > 0 { // draw empty circle if no values are defined at all mCategoryBrush.setColor( Qt::transparent ); p->setBrush( mCategoryBrush ); p->drawEllipse( baseX, baseY, w, h ); } }