QgsVectorLayer *QgsAuxiliaryLayer::toSpatialLayer() const { QgsVectorLayer *layer = QgsMemoryProviderUtils::createMemoryLayer( QStringLiteral( "auxiliary_layer" ), fields(), mLayer->wkbType(), mLayer->crs() ); QString pkField = mJoinInfo.targetFieldName(); QgsFeature joinFeature; QgsFeature targetFeature; QgsFeatureIterator it = getFeatures(); layer->startEditing(); while ( it.nextFeature( joinFeature ) ) { QString filter = QgsExpression::createFieldEqualityExpression( pkField, joinFeature.attribute( AS_JOINFIELD ) ); QgsFeatureRequest request; request.setFilterExpression( filter ); mLayer->getFeatures( request ).nextFeature( targetFeature ); if ( targetFeature.isValid() ) { QgsFeature newFeature( joinFeature ); newFeature.setGeometry( targetFeature.geometry() ); layer->addFeature( newFeature ); } } layer->commitChanges(); return layer; }
QgsFeatureRequest QgsRelation::getRelatedFeaturesRequest( const QgsFeature &feature ) const { QString filter = getRelatedFeaturesFilter( feature ); QgsDebugMsg( QStringLiteral( "Filter conditions: '%1'" ).arg( filter ) ); QgsFeatureRequest myRequest; myRequest.setFilterExpression( filter ); return myRequest; }
/** Filter the features of the layer */ void QgsAccessControl::filterFeatures( const QgsVectorLayer* layer, QgsFeatureRequest& featureRequest ) const { QStringList expressions = QStringList(); QgsAccessControlFilterMap::const_iterator acIterator; for ( acIterator = mPluginsAccessControls->constBegin(); acIterator != mPluginsAccessControls->constEnd(); ++acIterator ) { QString expression = acIterator.value()->layerFilterExpression( layer ); if ( !expression.isEmpty() ) { expressions.append( expression ); } } if ( !expressions.isEmpty() ) { featureRequest.setFilterExpression( QString( "((" ).append( expressions.join( ") AND (" ) ).append( "))" ) ); } }
QgsFeatureRequest QgsRelation::getReferencedFeatureRequest( const QgsAttributes &attributes ) const { QStringList conditions; for ( const FieldPair &pair : qgis::as_const( d->mFieldPairs ) ) { int referencingIdx = referencingLayer()->fields().indexFromName( pair.referencingField() ); conditions << QgsExpression::createFieldEqualityExpression( pair.referencedField(), attributes.at( referencingIdx ) ); } QgsFeatureRequest myRequest; QgsDebugMsg( QStringLiteral( "Filter conditions: '%1'" ).arg( conditions.join( " AND " ) ) ); myRequest.setFilterExpression( conditions.join( QStringLiteral( " AND " ) ) ); return myRequest; }
int QgsAtlasComposition::updateFeatures() { //needs to be called when layer, filter, sort changes if ( !mCoverageLayer ) { return 0; } QgsExpressionContext expressionContext = createExpressionContext(); updateFilenameExpression(); // select all features with all attributes QgsFeatureRequest req; QScopedPointer<QgsExpression> filterExpression; if ( mFilterFeatures && !mFeatureFilter.isEmpty() ) { filterExpression.reset( new QgsExpression( mFeatureFilter ) ); if ( filterExpression->hasParserError() ) { mFilterParserError = filterExpression->parserErrorString(); return 0; } //filter good to go req.setFilterExpression( mFeatureFilter ); } mFilterParserError = QString(); QgsFeatureIterator fit = mCoverageLayer->getFeatures( req ); QScopedPointer<QgsExpression> nameExpression; if ( !mPageNameExpression.isEmpty() ) { nameExpression.reset( new QgsExpression( mPageNameExpression ) ); if ( nameExpression->hasParserError() ) { nameExpression.reset( nullptr ); } else { nameExpression->prepare( &expressionContext ); } } // We cannot use nextFeature() directly since the feature pointer is rewinded by the rendering process // We thus store the feature ids for future extraction QgsFeature feat; mFeatureIds.clear(); mFeatureKeys.clear(); int sortIdx = mCoverageLayer->fields().lookupField( mSortKeyAttributeName ); while ( fit.nextFeature( feat ) ) { expressionContext.setFeature( feat ); QString pageName; if ( !nameExpression.isNull() ) { QVariant result = nameExpression->evaluate( &expressionContext ); if ( nameExpression->hasEvalError() ) { QgsMessageLog::logMessage( tr( "Atlas name eval error: %1" ).arg( nameExpression->evalErrorString() ), tr( "Composer" ) ); } pageName = result.toString(); } mFeatureIds.push_back( qMakePair( feat.id(), pageName ) ); if ( mSortFeatures && sortIdx != -1 ) { mFeatureKeys.insert( feat.id(), feat.attributes().at( sortIdx ) ); } } // sort features, if asked for if ( !mFeatureKeys.isEmpty() ) { FieldSorter sorter( mFeatureKeys, mSortAscending ); qSort( mFeatureIds.begin(), mFeatureIds.end(), sorter ); } emit numberFeaturesChanged( mFeatureIds.size() ); //jump to first feature if currently using an atlas preview //need to do this in case filtering/layer change has altered matching features if ( mComposition->atlasMode() == QgsComposition::PreviewAtlas ) { firstFeature(); } return mFeatureIds.size(); }
QVariantMap QgsExtractByExpressionAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); if ( !source ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) ); QString expressionString = parameterAsExpression( parameters, QStringLiteral( "EXPRESSION" ), context ); QString matchingSinkId; std::unique_ptr< QgsFeatureSink > matchingSink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, matchingSinkId, source->fields(), source->wkbType(), source->sourceCrs() ) ); if ( !matchingSink ) throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); QString nonMatchingSinkId; std::unique_ptr< QgsFeatureSink > nonMatchingSink( parameterAsSink( parameters, QStringLiteral( "FAIL_OUTPUT" ), context, nonMatchingSinkId, source->fields(), source->wkbType(), source->sourceCrs() ) ); QgsExpression expression( expressionString ); if ( expression.hasParserError() ) { throw QgsProcessingException( expression.parserErrorString() ); } QgsExpressionContext expressionContext = createExpressionContext( parameters, context, source.get() ); long count = source->featureCount(); double step = count > 0 ? 100.0 / count : 1; int current = 0; if ( !nonMatchingSink ) { // not saving failing features - so only fetch good features QgsFeatureRequest req; req.setFilterExpression( expressionString ); req.setExpressionContext( expressionContext ); QgsFeatureIterator it = source->getFeatures( req, QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks ); QgsFeature f; while ( it.nextFeature( f ) ) { if ( feedback->isCanceled() ) { break; } matchingSink->addFeature( f, QgsFeatureSink::FastInsert ); feedback->setProgress( current * step ); current++; } } else { // saving non-matching features, so we need EVERYTHING expressionContext.setFields( source->fields() ); expression.prepare( &expressionContext ); QgsFeatureIterator it = source->getFeatures(); QgsFeature f; while ( it.nextFeature( f ) ) { if ( feedback->isCanceled() ) { break; } expressionContext.setFeature( f ); if ( expression.evaluate( &expressionContext ).toBool() ) { matchingSink->addFeature( f, QgsFeatureSink::FastInsert ); } else { nonMatchingSink->addFeature( f, QgsFeatureSink::FastInsert ); } feedback->setProgress( current * step ); current++; } } QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), matchingSinkId ); if ( nonMatchingSink ) outputs.insert( QStringLiteral( "FAIL_OUTPUT" ), nonMatchingSinkId ); return outputs; }
int QgsLayoutAtlas::updateFeatures() { mCurrentFeatureNo = -1; if ( !mCoverageLayer ) { return 0; } QgsExpressionContext expressionContext = createExpressionContext(); QString error; updateFilenameExpression( error ); // select all features with all attributes QgsFeatureRequest req; req.setExpressionContext( expressionContext ); mFilterParserError.clear(); if ( mFilterFeatures && !mFilterExpression.isEmpty() ) { QgsExpression filterExpression( mFilterExpression ); if ( filterExpression.hasParserError() ) { mFilterParserError = filterExpression.parserErrorString(); return 0; } //filter good to go req.setFilterExpression( mFilterExpression ); } QgsFeatureIterator fit = mCoverageLayer->getFeatures( req ); std::unique_ptr<QgsExpression> nameExpression; if ( !mPageNameExpression.isEmpty() ) { nameExpression = qgis::make_unique< QgsExpression >( mPageNameExpression ); if ( nameExpression->hasParserError() ) { nameExpression.reset( nullptr ); } else { nameExpression->prepare( &expressionContext ); } } // We cannot use nextFeature() directly since the feature pointer is rewinded by the rendering process // We thus store the feature ids for future extraction QgsFeature feat; mFeatureIds.clear(); mFeatureKeys.clear(); std::unique_ptr<QgsExpression> sortExpression; if ( mSortFeatures && !mSortExpression.isEmpty() ) { sortExpression = qgis::make_unique< QgsExpression >( mSortExpression ); if ( sortExpression->hasParserError() ) { sortExpression.reset( nullptr ); } else { sortExpression->prepare( &expressionContext ); } } while ( fit.nextFeature( feat ) ) { expressionContext.setFeature( feat ); QString pageName; if ( nameExpression ) { QVariant result = nameExpression->evaluate( &expressionContext ); if ( nameExpression->hasEvalError() ) { QgsMessageLog::logMessage( tr( "Atlas name eval error: %1" ).arg( nameExpression->evalErrorString() ), tr( "Layout" ) ); } pageName = result.toString(); } mFeatureIds.push_back( qMakePair( feat.id(), pageName ) ); if ( sortExpression ) { QVariant result = sortExpression->evaluate( &expressionContext ); if ( sortExpression->hasEvalError() ) { QgsMessageLog::logMessage( tr( "Atlas sort eval error: %1" ).arg( sortExpression->evalErrorString() ), tr( "Layout" ) ); } mFeatureKeys.insert( feat.id(), result ); } } // sort features, if asked for if ( !mFeatureKeys.isEmpty() ) { AtlasFeatureSorter sorter( mFeatureKeys, mSortAscending ); std::sort( mFeatureIds.begin(), mFeatureIds.end(), sorter ); // clazy:exclude=detaching-member } emit numberFeaturesChanged( mFeatureIds.size() ); return mFeatureIds.size(); }
QVariantMap QgsJoinWithLinesAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { if ( parameters.value( QStringLiteral( "SPOKES" ) ) == parameters.value( QStringLiteral( "HUBS" ) ) ) throw QgsProcessingException( QObject::tr( "Same layer given for both hubs and spokes" ) ); std::unique_ptr< QgsProcessingFeatureSource > hubSource( parameterAsSource( parameters, QStringLiteral( "HUBS" ), context ) ); if ( !hubSource ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "HUBS" ) ) ); std::unique_ptr< QgsProcessingFeatureSource > spokeSource( parameterAsSource( parameters, QStringLiteral( "SPOKES" ), context ) ); if ( !hubSource || !spokeSource ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "SPOKES" ) ) ); QString fieldHubName = parameterAsString( parameters, QStringLiteral( "HUB_FIELD" ), context ); int fieldHubIndex = hubSource->fields().lookupField( fieldHubName ); const QStringList hubFieldsToCopy = parameterAsFields( parameters, QStringLiteral( "HUB_FIELDS" ), context ); QString fieldSpokeName = parameterAsString( parameters, QStringLiteral( "SPOKE_FIELD" ), context ); int fieldSpokeIndex = spokeSource->fields().lookupField( fieldSpokeName ); const QStringList spokeFieldsToCopy = parameterAsFields( parameters, QStringLiteral( "SPOKE_FIELDS" ), context ); if ( fieldHubIndex < 0 || fieldSpokeIndex < 0 ) throw QgsProcessingException( QObject::tr( "Invalid ID field" ) ); const bool geodesic = parameterAsBool( parameters, QStringLiteral( "GEODESIC" ), context ); const double geodesicDistance = parameterAsDouble( parameters, QStringLiteral( "GEODESIC_DISTANCE" ), context ) * 1000; bool dynamicGeodesicDistance = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "GEODESIC_DISTANCE" ) ); QgsExpressionContext expressionContext = createExpressionContext( parameters, context, hubSource.get() ); QgsProperty geodesicDistanceProperty; if ( dynamicGeodesicDistance ) { geodesicDistanceProperty = parameters.value( QStringLiteral( "GEODESIC_DISTANCE" ) ).value< QgsProperty >(); } const bool splitAntimeridian = parameterAsBool( parameters, QStringLiteral( "ANTIMERIDIAN_SPLIT" ), context ); QgsDistanceArea da; da.setSourceCrs( hubSource->sourceCrs(), context.transformContext() ); da.setEllipsoid( context.project()->ellipsoid() ); QgsFields hubOutFields; QgsAttributeList hubFieldIndices; if ( hubFieldsToCopy.empty() ) { hubOutFields = hubSource->fields(); hubFieldIndices.reserve( hubOutFields.count() ); for ( int i = 0; i < hubOutFields.count(); ++i ) { hubFieldIndices << i; } } else { hubFieldIndices.reserve( hubOutFields.count() ); for ( const QString &field : hubFieldsToCopy ) { int index = hubSource->fields().lookupField( field ); if ( index >= 0 ) { hubFieldIndices << index; hubOutFields.append( hubSource->fields().at( index ) ); } } } QgsAttributeList hubFields2Fetch = hubFieldIndices; hubFields2Fetch << fieldHubIndex; QgsFields spokeOutFields; QgsAttributeList spokeFieldIndices; if ( spokeFieldsToCopy.empty() ) { spokeOutFields = spokeSource->fields(); spokeFieldIndices.reserve( spokeOutFields.count() ); for ( int i = 0; i < spokeOutFields.count(); ++i ) { spokeFieldIndices << i; } } else { for ( const QString &field : spokeFieldsToCopy ) { int index = spokeSource->fields().lookupField( field ); if ( index >= 0 ) { spokeFieldIndices << index; spokeOutFields.append( spokeSource->fields().at( index ) ); } } } QgsAttributeList spokeFields2Fetch = spokeFieldIndices; spokeFields2Fetch << fieldSpokeIndex; QgsFields fields = QgsProcessingUtils::combineFields( hubOutFields, spokeOutFields ); QgsWkbTypes::Type outType = geodesic ? QgsWkbTypes::MultiLineString : QgsWkbTypes::LineString; bool hasZ = false; if ( QgsWkbTypes::hasZ( hubSource->wkbType() ) || QgsWkbTypes::hasZ( spokeSource->wkbType() ) ) { outType = QgsWkbTypes::addZ( outType ); hasZ = true; } bool hasM = false; if ( QgsWkbTypes::hasM( hubSource->wkbType() ) || QgsWkbTypes::hasM( spokeSource->wkbType() ) ) { outType = QgsWkbTypes::addM( outType ); hasM = true; } QString dest; std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, outType, hubSource->sourceCrs(), QgsFeatureSink::RegeneratePrimaryKey ) ); if ( !sink ) throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); auto getPointFromFeature = [hasZ, hasM]( const QgsFeature & feature )->QgsPoint { QgsPoint p; if ( feature.geometry().type() == QgsWkbTypes::PointGeometry && !feature.geometry().isMultipart() ) p = *static_cast< const QgsPoint *>( feature.geometry().constGet() ); else p = *static_cast< const QgsPoint *>( feature.geometry().pointOnSurface().constGet() ); if ( hasZ && !p.is3D() ) p.addZValue( 0 ); if ( hasM && !p.isMeasure() ) p.addMValue( 0 ); return p; }; QgsFeatureIterator hubFeatures = hubSource->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( hubFields2Fetch ), QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks ); double step = hubSource->featureCount() > 0 ? 100.0 / hubSource->featureCount() : 1; int i = 0; QgsFeature hubFeature; while ( hubFeatures.nextFeature( hubFeature ) ) { i++; if ( feedback->isCanceled() ) { break; } feedback->setProgress( i * step ); if ( !hubFeature.hasGeometry() ) continue; QgsPoint hubPoint = getPointFromFeature( hubFeature ); // only keep selected attributes QgsAttributes hubAttributes; for ( int j = 0; j < hubFeature.attributes().count(); ++j ) { if ( !hubFieldIndices.contains( j ) ) continue; hubAttributes << hubFeature.attribute( j ); } QgsFeatureRequest spokeRequest = QgsFeatureRequest().setDestinationCrs( hubSource->sourceCrs(), context.transformContext() ); spokeRequest.setSubsetOfAttributes( spokeFields2Fetch ); spokeRequest.setFilterExpression( QgsExpression::createFieldEqualityExpression( fieldSpokeName, hubFeature.attribute( fieldHubIndex ) ) ); QgsFeatureIterator spokeFeatures = spokeSource->getFeatures( spokeRequest, QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks ); QgsFeature spokeFeature; while ( spokeFeatures.nextFeature( spokeFeature ) ) { if ( feedback->isCanceled() ) { break; } if ( !spokeFeature.hasGeometry() ) continue; QgsPoint spokePoint = getPointFromFeature( spokeFeature ); QgsGeometry line; if ( !geodesic ) { line = QgsGeometry( new QgsLineString( QVector< QgsPoint >() << hubPoint << spokePoint ) ); if ( splitAntimeridian ) line = da.splitGeometryAtAntimeridian( line ); } else { double distance = geodesicDistance; if ( dynamicGeodesicDistance ) { expressionContext.setFeature( hubFeature ); distance = geodesicDistanceProperty.valueAsDouble( expressionContext, distance ); } std::unique_ptr< QgsMultiLineString > ml = qgis::make_unique< QgsMultiLineString >(); std::unique_ptr< QgsLineString > l = qgis::make_unique< QgsLineString >( QVector< QgsPoint >() << hubPoint ); QVector< QVector< QgsPointXY > > points = da.geodesicLine( QgsPointXY( hubPoint ), QgsPointXY( spokePoint ), distance, splitAntimeridian ); QVector< QgsPointXY > points1 = points.at( 0 ); points1.pop_front(); if ( points.count() == 1 ) points1.pop_back(); QgsLineString geodesicPoints( points1 ); l->append( &geodesicPoints ); if ( points.count() == 1 ) l->addVertex( spokePoint ); ml->addGeometry( l.release() ); if ( points.count() > 1 ) { QVector< QgsPointXY > points2 = points.at( 1 ); points2.pop_back(); l = qgis::make_unique< QgsLineString >( points2 ); if ( hasZ ) l->addZValue( std::numeric_limits<double>::quiet_NaN() ); if ( hasM ) l->addMValue( std::numeric_limits<double>::quiet_NaN() ); l->addVertex( spokePoint ); ml->addGeometry( l.release() ); } line = QgsGeometry( std::move( ml ) ); } QgsFeature outFeature; QgsAttributes outAttributes = hubAttributes; // only keep selected attributes QgsAttributes spokeAttributes; for ( int j = 0; j < spokeFeature.attributes().count(); ++j ) { if ( !spokeFieldIndices.contains( j ) ) continue; spokeAttributes << spokeFeature.attribute( j ); } outAttributes.append( spokeAttributes ); outFeature.setAttributes( outAttributes ); outFeature.setGeometry( line ); sink->addFeature( outFeature, QgsFeatureSink::FastInsert ); } } QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), dest ); return outputs; }
bool QgsVectorLayerRenderer::render() { if ( mGeometryType == QGis::NoGeometry || mGeometryType == QGis::UnknownGeometry ) return true; if ( !mRendererV2 ) { mErrors.append( QObject::tr( "No renderer for drawing." ) ); return false; } bool usingEffect = false; if ( mRendererV2->paintEffect() && mRendererV2->paintEffect()->enabled() ) { usingEffect = true; mRendererV2->paintEffect()->begin( mContext ); } // Per feature blending mode if ( mContext.useAdvancedEffects() && mFeatureBlendMode != QPainter::CompositionMode_SourceOver ) { // set the painter to the feature blend mode, so that features drawn // on this layer will interact and blend with each other mContext.painter()->setCompositionMode( mFeatureBlendMode ); } mRendererV2->startRender( mContext, mFields ); QString rendererFilter = mRendererV2->filter(); QgsRectangle requestExtent = mContext.extent(); mRendererV2->modifyRequestExtent( requestExtent, mContext ); QgsFeatureRequest featureRequest = QgsFeatureRequest() .setFilterRect( requestExtent ) .setSubsetOfAttributes( mAttrNames, mFields ); if ( !rendererFilter.isEmpty() ) { featureRequest.setFilterExpression( rendererFilter ); featureRequest.setExpressionContext( mContext.expressionContext() ); } // enable the simplification of the geometries (Using the current map2pixel context) before send it to renderer engine. if ( mSimplifyGeometry ) { double map2pixelTol = mSimplifyMethod.threshold(); bool validTransform = true; const QgsMapToPixel& mtp = mContext.mapToPixel(); map2pixelTol *= mtp.mapUnitsPerPixel(); const QgsCoordinateTransform* ct = mContext.coordinateTransform(); // resize the tolerance using the change of size of an 1-BBOX from the source CoordinateSystem to the target CoordinateSystem if ( ct && !(( QgsCoordinateTransform* )ct )->isShortCircuited() ) { try { QgsPoint center = mContext.extent().center(); double rectSize = ct->sourceCrs().geographicFlag() ? 0.0008983 /* ~100/(40075014/360=111319.4833) */ : 100; QgsRectangle sourceRect = QgsRectangle( center.x(), center.y(), center.x() + rectSize, center.y() + rectSize ); QgsRectangle targetRect = ct->transform( sourceRect ); QgsDebugMsg( QString( "Simplify - SourceTransformRect=%1" ).arg( sourceRect.toString( 16 ) ) ); QgsDebugMsg( QString( "Simplify - TargetTransformRect=%1" ).arg( targetRect.toString( 16 ) ) ); if ( !sourceRect.isEmpty() && sourceRect.isFinite() && !targetRect.isEmpty() && targetRect.isFinite() ) { QgsPoint minimumSrcPoint( sourceRect.xMinimum(), sourceRect.yMinimum() ); QgsPoint maximumSrcPoint( sourceRect.xMaximum(), sourceRect.yMaximum() ); QgsPoint minimumDstPoint( targetRect.xMinimum(), targetRect.yMinimum() ); QgsPoint maximumDstPoint( targetRect.xMaximum(), targetRect.yMaximum() ); double sourceHypothenuse = sqrt( minimumSrcPoint.sqrDist( maximumSrcPoint ) ); double targetHypothenuse = sqrt( minimumDstPoint.sqrDist( maximumDstPoint ) ); QgsDebugMsg( QString( "Simplify - SourceHypothenuse=%1" ).arg( sourceHypothenuse ) ); QgsDebugMsg( QString( "Simplify - TargetHypothenuse=%1" ).arg( targetHypothenuse ) ); if ( targetHypothenuse != 0 ) map2pixelTol *= ( sourceHypothenuse / targetHypothenuse ); } } catch ( QgsCsException &cse ) { QgsMessageLog::logMessage( QObject::tr( "Simplify transform error caught: %1" ).arg( cse.what() ), QObject::tr( "CRS" ) ); validTransform = false; } } if ( validTransform ) { QgsSimplifyMethod simplifyMethod; simplifyMethod.setMethodType( QgsSimplifyMethod::OptimizeForRendering ); simplifyMethod.setTolerance( map2pixelTol ); simplifyMethod.setForceLocalOptimization( mSimplifyMethod.forceLocalOptimization() ); featureRequest.setSimplifyMethod( simplifyMethod ); QgsVectorSimplifyMethod vectorMethod = mSimplifyMethod; mContext.setVectorSimplifyMethod( vectorMethod ); } else { QgsVectorSimplifyMethod vectorMethod; vectorMethod.setSimplifyHints( QgsVectorSimplifyMethod::NoSimplification ); mContext.setVectorSimplifyMethod( vectorMethod ); } } else { QgsVectorSimplifyMethod vectorMethod; vectorMethod.setSimplifyHints( QgsVectorSimplifyMethod::NoSimplification ); mContext.setVectorSimplifyMethod( vectorMethod ); } QgsFeatureIterator fit = mSource->getFeatures( featureRequest ); if (( mRendererV2->capabilities() & QgsFeatureRendererV2::SymbolLevels ) && mRendererV2->usingSymbolLevels() ) drawRendererV2Levels( fit ); else drawRendererV2( fit ); if ( usingEffect ) { mRendererV2->paintEffect()->end( mContext ); } //apply layer transparency for vector layers if ( mContext.useAdvancedEffects() && mLayerTransparency != 0 ) { // a layer transparency has been set, so update the alpha for the flattened layer // by combining it with the layer transparency QColor transparentFillColor = QColor( 0, 0, 0, 255 - ( 255 * mLayerTransparency / 100 ) ); // use destination in composition mode to merge source's alpha with destination mContext.painter()->setCompositionMode( QPainter::CompositionMode_DestinationIn ); mContext.painter()->fillRect( 0, 0, mContext.painter()->device()->width(), mContext.painter()->device()->height(), transparentFillColor ); } return true; }
QVariant QgsAggregateCalculator::calculate( QgsAggregateCalculator::Aggregate aggregate, const QString& fieldOrExpression, QgsExpressionContext* context, bool* ok ) const { if ( ok ) *ok = false; if ( !mLayer ) return QVariant(); QScopedPointer<QgsExpression> expression; QScopedPointer<QgsExpressionContext> defaultContext; if ( !context ) { defaultContext.reset( createContext() ); context = defaultContext.data(); } int attrNum = mLayer->fieldNameIndex( fieldOrExpression ); if ( attrNum == -1 ) { Q_ASSERT( context ); context->setFields( mLayer->fields() ); // try to use expression expression.reset( new QgsExpression( fieldOrExpression ) ); if ( expression->hasParserError() || !expression->prepare( context ) ) { return QVariant(); } } QStringList lst; if ( expression.isNull() ) lst.append( fieldOrExpression ); else lst = expression->referencedColumns(); QgsFeatureRequest request = QgsFeatureRequest() .setFlags(( expression.data() && expression->needsGeometry() ) ? QgsFeatureRequest::NoFlags : QgsFeatureRequest::NoGeometry ) .setSubsetOfAttributes( lst, mLayer->fields() ); if ( !mFilterExpression.isEmpty() ) request.setFilterExpression( mFilterExpression ); if ( context ) request.setExpressionContext( *context ); //determine result type QVariant::Type resultType = QVariant::Double; if ( attrNum == -1 ) { // evaluate first feature, check result type QgsFeatureRequest testRequest( request ); testRequest.setLimit( 1 ); QgsFeature f; QgsFeatureIterator fit = mLayer->getFeatures( testRequest ); if ( !fit.nextFeature( f ) ) { //no matching features if ( ok ) *ok = true; return QVariant(); } if ( context ) context->setFeature( f ); QVariant v = expression->evaluate( context ); resultType = v.type(); } else { resultType = mLayer->fields().at( attrNum ).type(); } QgsFeatureIterator fit = mLayer->getFeatures( request ); return calculate( aggregate, fit, resultType, attrNum, expression.data(), mDelimiter, context, ok ); }
QgsFeatureRequest parseFilterElement( const QString &typeName, QDomElement &filterElem, const QgsProject *project ) { QgsFeatureRequest request; QDomNodeList fidNodes = filterElem.elementsByTagName( QStringLiteral( "FeatureId" ) ); QDomNodeList goidNodes = filterElem.elementsByTagName( QStringLiteral( "GmlObjectId" ) ); if ( !fidNodes.isEmpty() ) { QgsFeatureIds fids; QDomElement fidElem; for ( int f = 0; f < fidNodes.size(); f++ ) { fidElem = fidNodes.at( f ).toElement(); if ( !fidElem.hasAttribute( QStringLiteral( "fid" ) ) ) { throw QgsRequestNotWellFormedException( "FeatureId element without fid attribute" ); } QString fid = fidElem.attribute( QStringLiteral( "fid" ) ); if ( fid.contains( QLatin1String( "." ) ) ) { if ( fid.section( QStringLiteral( "." ), 0, 0 ) != typeName ) continue; fid = fid.section( QStringLiteral( "." ), 1, 1 ); } fids.insert( fid.toInt() ); } if ( !fids.isEmpty() ) { request.setFilterFids( fids ); } else { throw QgsRequestNotWellFormedException( QStringLiteral( "No FeatureId element correctly parse against typeName '%1'" ).arg( typeName ) ); } request.setFlags( QgsFeatureRequest::NoFlags ); return request; } else if ( !goidNodes.isEmpty() ) { QgsFeatureIds fids; QDomElement goidElem; for ( int f = 0; f < goidNodes.size(); f++ ) { goidElem = goidNodes.at( f ).toElement(); if ( !goidElem.hasAttribute( QStringLiteral( "id" ) ) && !goidElem.hasAttribute( QStringLiteral( "gml:id" ) ) ) { throw QgsRequestNotWellFormedException( "GmlObjectId element without gml:id attribute" ); } QString fid = goidElem.attribute( QStringLiteral( "id" ) ); if ( fid.isEmpty() ) fid = goidElem.attribute( QStringLiteral( "gml:id" ) ); if ( fid.contains( QLatin1String( "." ) ) ) { if ( fid.section( QStringLiteral( "." ), 0, 0 ) != typeName ) continue; fid = fid.section( QStringLiteral( "." ), 1, 1 ); } fids.insert( fid.toInt() ); } if ( !fids.isEmpty() ) { request.setFilterFids( fids ); } else { throw QgsRequestNotWellFormedException( QStringLiteral( "No GmlObjectId element correctly parse against typeName '%1'" ).arg( typeName ) ); } request.setFlags( QgsFeatureRequest::NoFlags ); return request; } else if ( filterElem.firstChildElement().tagName() == QLatin1String( "BBOX" ) ) { QDomElement bboxElem = filterElem.firstChildElement(); QDomElement childElem = bboxElem.firstChildElement(); while ( !childElem.isNull() ) { if ( childElem.tagName() == QLatin1String( "Box" ) ) { request.setFilterRect( QgsOgcUtils::rectangleFromGMLBox( childElem ) ); } else if ( childElem.tagName() != QLatin1String( "PropertyName" ) ) { QgsGeometry geom = QgsOgcUtils::geometryFromGML( childElem ); request.setFilterRect( geom.boundingBox() ); } childElem = childElem.nextSiblingElement(); } request.setFlags( QgsFeatureRequest::ExactIntersect | QgsFeatureRequest::NoFlags ); return request; } // Apply BBOX through filterRect even inside an And to use spatial index else if ( filterElem.firstChildElement().tagName() == QLatin1String( "And" ) && !filterElem.firstChildElement().firstChildElement( QLatin1String( "BBOX" ) ).isNull() ) { QDomElement childElem = filterElem.firstChildElement().firstChildElement(); while ( !childElem.isNull() ) { QDomElement childFilterElement = filterElem.ownerDocument().createElement( QLatin1String( "Filter" ) ); childFilterElement.appendChild( childElem.cloneNode( true ) ); QgsFeatureRequest childRequest = parseFilterElement( typeName, childFilterElement ); if ( childElem.tagName() == QLatin1String( "BBOX" ) ) { if ( request.filterRect().isEmpty() ) { request.setFilterRect( childRequest.filterRect() ); } else { request.setFilterRect( request.filterRect().intersect( childRequest.filterRect() ) ); } } else { if ( !request.filterExpression() ) { request.setFilterExpression( childRequest.filterExpression()->expression() ); } else { QgsExpressionNode *opLeft = request.filterExpression()->rootNode()->clone(); QgsExpressionNode *opRight = childRequest.filterExpression()->rootNode()->clone(); std::unique_ptr<QgsExpressionNodeBinaryOperator> node = qgis::make_unique<QgsExpressionNodeBinaryOperator>( QgsExpressionNodeBinaryOperator::boAnd, opLeft, opRight ); QgsExpression expr( node->dump() ); request.setFilterExpression( expr ); } } childElem = childElem.nextSiblingElement(); } request.setFlags( QgsFeatureRequest::ExactIntersect | QgsFeatureRequest::NoFlags ); return request; } else { QgsVectorLayer *layer = nullptr; if ( project != nullptr ) { layer = layerByTypeName( project, typeName ); } std::shared_ptr<QgsExpression> filter( QgsOgcUtils::expressionFromOgcFilter( filterElem, layer ) ); if ( filter ) { if ( filter->hasParserError() ) { throw QgsRequestNotWellFormedException( filter->parserErrorString() ); } if ( filter->needsGeometry() ) { request.setFlags( QgsFeatureRequest::NoFlags ); } request.setFilterExpression( filter->expression() ); return request; } } return request; }
QVariantMap QgsJoinWithLinesAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { if ( parameters.value( QStringLiteral( "SPOKES" ) ) == parameters.value( QStringLiteral( "HUBS" ) ) ) throw QgsProcessingException( QObject::tr( "Same layer given for both hubs and spokes" ) ); std::unique_ptr< QgsFeatureSource > hubSource( parameterAsSource( parameters, QStringLiteral( "HUBS" ), context ) ); std::unique_ptr< QgsFeatureSource > spokeSource( parameterAsSource( parameters, QStringLiteral( "SPOKES" ), context ) ); if ( !hubSource || !spokeSource ) return QVariantMap(); QString fieldHubName = parameterAsString( parameters, QStringLiteral( "HUB_FIELD" ), context ); int fieldHubIndex = hubSource->fields().lookupField( fieldHubName ); const QStringList hubFieldsToCopy = parameterAsFields( parameters, QStringLiteral( "HUB_FIELDS" ), context ); QString fieldSpokeName = parameterAsString( parameters, QStringLiteral( "SPOKE_FIELD" ), context ); int fieldSpokeIndex = spokeSource->fields().lookupField( fieldSpokeName ); const QStringList spokeFieldsToCopy = parameterAsFields( parameters, QStringLiteral( "SPOKE_FIELDS" ), context ); if ( fieldHubIndex < 0 || fieldSpokeIndex < 0 ) throw QgsProcessingException( QObject::tr( "Invalid ID field" ) ); QgsFields hubOutFields; QgsAttributeList hubFieldIndices; if ( hubFieldsToCopy.empty() ) { hubOutFields = hubSource->fields(); for ( int i = 0; i < hubOutFields.count(); ++i ) { hubFieldIndices << i; } } else { for ( const QString &field : hubFieldsToCopy ) { int index = hubSource->fields().lookupField( field ); if ( index >= 0 ) { hubFieldIndices << index; hubOutFields.append( hubSource->fields().at( index ) ); } } } QgsAttributeList hubFields2Fetch = hubFieldIndices; hubFields2Fetch << fieldHubIndex; QgsFields spokeOutFields; QgsAttributeList spokeFieldIndices; if ( spokeFieldsToCopy.empty() ) { spokeOutFields = spokeSource->fields(); for ( int i = 0; i < spokeOutFields.count(); ++i ) { spokeFieldIndices << i; } } else { for ( const QString &field : spokeFieldsToCopy ) { int index = spokeSource->fields().lookupField( field ); if ( index >= 0 ) { spokeFieldIndices << index; spokeOutFields.append( spokeSource->fields().at( index ) ); } } } QgsAttributeList spokeFields2Fetch = spokeFieldIndices; spokeFields2Fetch << fieldSpokeIndex; QgsFields fields = QgsProcessingUtils::combineFields( hubOutFields, spokeOutFields ); QgsWkbTypes::Type outType = QgsWkbTypes::LineString; bool hasZ = false; if ( QgsWkbTypes::hasZ( hubSource->wkbType() ) || QgsWkbTypes::hasZ( spokeSource->wkbType() ) ) { outType = QgsWkbTypes::addZ( outType ); hasZ = true; } bool hasM = false; if ( QgsWkbTypes::hasM( hubSource->wkbType() ) || QgsWkbTypes::hasM( spokeSource->wkbType() ) ) { outType = QgsWkbTypes::addM( outType ); hasM = true; } QString dest; std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, outType, hubSource->sourceCrs() ) ); if ( !sink ) return QVariantMap(); auto getPointFromFeature = [hasZ, hasM]( const QgsFeature & feature )->QgsPoint { QgsPoint p; if ( feature.geometry().type() == QgsWkbTypes::PointGeometry && !feature.geometry().isMultipart() ) p = *static_cast< const QgsPoint *>( feature.geometry().constGet() ); else p = *static_cast< const QgsPoint *>( feature.geometry().pointOnSurface().constGet() ); if ( hasZ && !p.is3D() ) p.addZValue( 0 ); if ( hasM && !p.isMeasure() ) p.addMValue( 0 ); return p; }; QgsFeatureIterator hubFeatures = hubSource->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( hubFields2Fetch ) ); double step = hubSource->featureCount() > 0 ? 100.0 / hubSource->featureCount() : 1; int i = 0; QgsFeature hubFeature; while ( hubFeatures.nextFeature( hubFeature ) ) { i++; if ( feedback->isCanceled() ) { break; } feedback->setProgress( i * step ); if ( !hubFeature.hasGeometry() ) continue; QgsPoint hubPoint = getPointFromFeature( hubFeature ); // only keep selected attributes QgsAttributes hubAttributes; for ( int j = 0; j < hubFeature.attributes().count(); ++j ) { if ( !hubFieldIndices.contains( j ) ) continue; hubAttributes << hubFeature.attribute( j ); } QgsFeatureRequest spokeRequest = QgsFeatureRequest().setDestinationCrs( hubSource->sourceCrs(), context.transformContext() ); spokeRequest.setSubsetOfAttributes( spokeFields2Fetch ); spokeRequest.setFilterExpression( QgsExpression::createFieldEqualityExpression( fieldSpokeName, hubFeature.attribute( fieldHubIndex ) ) ); QgsFeatureIterator spokeFeatures = spokeSource->getFeatures( spokeRequest ); QgsFeature spokeFeature; while ( spokeFeatures.nextFeature( spokeFeature ) ) { if ( feedback->isCanceled() ) { break; } if ( !spokeFeature.hasGeometry() ) continue; QgsPoint spokePoint = getPointFromFeature( spokeFeature ); QgsGeometry line( new QgsLineString( QVector< QgsPoint >() << hubPoint << spokePoint ) ); QgsFeature outFeature; QgsAttributes outAttributes = hubAttributes; // only keep selected attributes QgsAttributes spokeAttributes; for ( int j = 0; j < spokeFeature.attributes().count(); ++j ) { if ( !spokeFieldIndices.contains( j ) ) continue; spokeAttributes << spokeFeature.attribute( j ); } outAttributes.append( spokeAttributes ); outFeature.setAttributes( outAttributes ); outFeature.setGeometry( line ); sink->addFeature( outFeature, QgsFeatureSink::FastInsert ); } } QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), dest ); return outputs; }