QgsFeature QgsConvexHullAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback *feedback ) { QgsFeature f = feature; if ( f.hasGeometry() ) { QgsGeometry outputGeometry = f.geometry().convexHull(); if ( !outputGeometry ) feedback->reportError( outputGeometry.lastError() ); f.setGeometry( outputGeometry ); if ( outputGeometry ) { QgsAttributes attrs = f.attributes(); attrs << outputGeometry.constGet()->area() << outputGeometry.constGet()->perimeter(); f.setAttributes( attrs ); } else { QgsAttributes attrs = f.attributes(); attrs << QVariant() << QVariant(); f.setAttributes( attrs ); } } return f; }
QgsFeatureList QgsConvexHullAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback *feedback ) { QgsFeature f = feature; if ( f.hasGeometry() ) { QgsGeometry outputGeometry; if ( QgsWkbTypes::flatType( f.geometry().wkbType() ) == QgsWkbTypes::Point ) { feedback->reportError( QObject::tr( "Cannot calculate convex hull for a single Point feature (try 'Minimum bounding geometry' algorithm instead)." ) ); f.clearGeometry(); } else { outputGeometry = f.geometry().convexHull(); if ( outputGeometry.isNull() ) feedback->reportError( outputGeometry.lastError() ); f.setGeometry( outputGeometry ); } if ( !outputGeometry.isNull() ) { QgsAttributes attrs = f.attributes(); attrs << outputGeometry.constGet()->area() << outputGeometry.constGet()->perimeter(); f.setAttributes( attrs ); } else { QgsAttributes attrs = f.attributes(); attrs << QVariant() << QVariant(); f.setAttributes( attrs ); } } return QgsFeatureList() << f; }
void QgsVectorLayerFeatureIterator::useAddedFeature( const QgsFeature& src, QgsFeature& f ) { f.setFeatureId( src.id() ); f.setValid( true ); f.setFields( &L->mUpdatedFields ); if ( src.geometry() && !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) { f.setGeometry( *src.geometry() ); // simplify the edited geometry using its simplifier configured if ( mEditGeometrySimplifier ) { QgsGeometry* geometry = f.geometry(); QGis::GeometryType geometryType = geometry->type(); if ( geometryType == QGis::Line || geometryType == QGis::Polygon ) mEditGeometrySimplifier->simplifyGeometry( geometry ); } } // TODO[MD]: if subset set just some attributes f.setAttributes( src.attributes() ); if ( !mFetchJoinInfo.isEmpty() ) addJoinedAttributes( f ); }
void QgsVectorLayerFeatureIterator::useChangedAttributeFeature( QgsFeatureId fid, const QgsGeometry& geom, QgsFeature& f ) { f.setFeatureId( fid ); f.setValid( true ); f.setFields( &L->mUpdatedFields ); if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) f.setGeometry( geom ); bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ); if ( !subsetAttrs || ( subsetAttrs && mRequest.subsetOfAttributes().count() > 0 ) ) { // retrieve attributes from provider QgsFeature tmp; //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes ); QgsFeatureRequest request; request.setFilterFid( fid ).setFlags( QgsFeatureRequest::NoGeometry ).setSubsetOfAttributes( mProviderRequest.subsetOfAttributes() ); QgsFeatureIterator fi = L->dataProvider()->getFeatures( request ); if ( fi.nextFeature( tmp ) ) { updateChangedAttributes( tmp ); f.setAttributes( tmp.attributes() ); } } if ( !mFetchJoinInfo.isEmpty() ) addJoinedAttributes( f ); }
QgsFeatureList QgsAddXYFieldsAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { if ( mTransformNeedsInitialization ) { mTransform = QgsCoordinateTransform( mSourceCrs, mCrs, context.transformContext() ); mTransformNeedsInitialization = false; } QVariant x; QVariant y; if ( feature.hasGeometry() ) { if ( feature.geometry().isMultipart() ) throw QgsProcessingException( QObject::tr( "Multipoint features are not supported - please convert to single point features first." ) ); const QgsPointXY point = feature.geometry().asPoint(); try { const QgsPointXY transformed = mTransform.transform( point ); x = transformed.x(); y = transformed.y(); } catch ( QgsCsException & ) { feedback->reportError( QObject::tr( "Could not transform point to destination CRS" ) ); } } QgsFeature f = feature; QgsAttributes attributes = f.attributes(); attributes << x << y; f.setAttributes( attributes ); return QgsFeatureList() << f; }
void QgsMapToolOffsetCurve::canvasReleaseEvent( QMouseEvent * e ) { Q_UNUSED( e ); QgsVectorLayer* vlayer = currentVectorLayer(); if ( !vlayer ) { deleteRubberBandAndGeometry(); return; } if ( !mGeometryModified ) { deleteRubberBandAndGeometry(); vlayer->destroyEditCommand(); return; } if ( mMultiPartGeometry ) { mModifiedGeometry.convertToMultiType(); } vlayer->beginEditCommand( tr( "Offset curve" ) ); bool editOk; if ( mSourceLayerId == vlayer->id() && !mForceCopy ) { editOk = vlayer->changeGeometry( mModifiedFeature, &mModifiedGeometry ); } else { QgsFeature f; f.setGeometry( mModifiedGeometry ); //add empty values for all fields (allows inserting attribute values via the feature form in the same session) QgsAttributes attrs( vlayer->pendingFields().count() ); const QgsFields& fields = vlayer->pendingFields(); for ( int idx = 0; idx < fields.count(); ++idx ) { attrs[idx] = QVariant(); } f.setAttributes( attrs ); editOk = vlayer->addFeature( f ); } if ( editOk ) { vlayer->endEditCommand(); } else { vlayer->destroyEditCommand(); } deleteRubberBandAndGeometry(); deleteDistanceItem(); delete mSnapVertexMarker; mSnapVertexMarker = 0; mForceCopy = false; mCanvas->refresh(); }
QgsVectorLayer *QgsFeatureSource::materialize( const QgsFeatureRequest &request, QgsFeedback *feedback ) { QgsWkbTypes::Type outWkbType = request.flags() & QgsFeatureRequest::NoGeometry ? QgsWkbTypes::NoGeometry : wkbType(); QgsCoordinateReferenceSystem crs = request.destinationCrs().isValid() ? request.destinationCrs() : sourceCrs(); QgsAttributeList requestedAttrs = request.subsetOfAttributes(); QgsFields outFields; if ( request.flags() & QgsFeatureRequest::SubsetOfAttributes ) { int i = 0; const QgsFields sourceFields = fields(); for ( const QgsField &field : sourceFields ) { if ( requestedAttrs.contains( i ) ) outFields.append( field ); i++; } } else { outFields = fields(); } std::unique_ptr< QgsVectorLayer > layer( QgsMemoryProviderUtils::createMemoryLayer( sourceName(), outFields, outWkbType, crs ) ); QgsFeature f; QgsFeatureIterator it = getFeatures( request ); int fieldCount = fields().count(); while ( it.nextFeature( f ) ) { if ( feedback && feedback->isCanceled() ) break; if ( request.flags() & QgsFeatureRequest::SubsetOfAttributes ) { // remove unused attributes QgsAttributes attrs; for ( int i = 0; i < fieldCount; ++i ) { if ( requestedAttrs.contains( i ) ) { attrs.append( f.attributes().at( i ) ); } } f.setAttributes( attrs ); } layer->dataProvider()->addFeature( f, QgsFeatureSink::FastInsert ); } return layer.release(); }
void QgsGeometryAnalyzer::bufferFeature( QgsFeature& f, int nProcessedFeatures, QgsVectorFileWriter* vfw, bool dissolve, QgsGeometry** dissolveGeometry, double bufferDistance, int bufferDistanceField ) { double currentBufferDistance; QgsGeometry* featureGeometry = f.geometry(); QgsGeometry* tmpGeometry = 0; QgsGeometry* bufferGeometry = 0; if ( !featureGeometry ) { return; } //create buffer if ( bufferDistanceField == -1 ) { currentBufferDistance = bufferDistance; } else { currentBufferDistance = f.attribute( bufferDistanceField ).toDouble(); } bufferGeometry = featureGeometry->buffer( currentBufferDistance, 5 ); if ( dissolve ) { if ( nProcessedFeatures == 0 ) { *dissolveGeometry = bufferGeometry; } else { tmpGeometry = *dissolveGeometry; *dissolveGeometry = ( *dissolveGeometry )->combine( bufferGeometry ); delete tmpGeometry; delete bufferGeometry; } } else //dissolve { QgsFeature newFeature; newFeature.setGeometry( bufferGeometry ); newFeature.setAttributes( f.attributes() ); //add it to vector file writer if ( vfw ) { vfw->addFeature( newFeature ); } } }
QgsFeatureList QgsMinimumEnclosingCircleAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback * ) { QgsFeature f = feature; if ( f.hasGeometry() ) { double radius = 0; QgsPointXY center; QgsGeometry outputGeometry = f.geometry().minimalEnclosingCircle( center, radius, mSegments ); f.setGeometry( outputGeometry ); QgsAttributes attrs = f.attributes(); attrs << radius << M_PI *radius *radius; f.setAttributes( attrs ); } else { QgsAttributes attrs = f.attributes(); attrs << QVariant() << QVariant(); f.setAttributes( attrs ); } return QgsFeatureList() << f; }
void QgsVectorLayerFeatureIterator::useAddedFeature( const QgsFeature& src, QgsFeature& f ) { f.setFeatureId( src.id() ); f.setValid( true ); f.setFields( &L->mUpdatedFields ); if ( src.geometry() && !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) f.setGeometry( *src.geometry() ); // TODO[MD]: if subset set just some attributes f.setAttributes( src.attributes() ); if ( !mFetchJoinInfo.isEmpty() ) addJoinedAttributes( f ); }
void QgsGeometryAnalyzer::centroidFeature( QgsFeature& f, QgsVectorFileWriter* vfw ) { if ( !f.hasGeometry() ) { return; } QgsGeometry featureGeometry = f.geometry(); QgsFeature newFeature; newFeature.setGeometry( featureGeometry.centroid() ); newFeature.setAttributes( f.attributes() ); //add it to vector file writer if ( vfw ) { vfw->addFeature( newFeature ); } }
void QgsVectorLayerDiagramProvider::drawLabel( QgsRenderContext &context, pal::LabelPosition *label ) const { #if 1 // XXX strk // features are pre-rotated but not scaled/translated, // so we only disable rotation here. Ideally, they'd be // also pre-scaled/translated, as suggested here: // https://issues.qgis.org/issues/11856 QgsMapToPixel xform = context.mapToPixel(); xform.setMapRotation( 0, 0, 0 ); #else const QgsMapToPixel &xform = context.mapToPixel(); #endif QgsDiagramLabelFeature *dlf = dynamic_cast<QgsDiagramLabelFeature *>( label->getFeaturePart()->feature() ); QgsFeature feature; feature.setFields( mFields ); feature.setValid( true ); feature.setId( label->getFeaturePart()->featureId() ); feature.setAttributes( dlf->attributes() ); context.expressionContext().setFeature( feature ); //calculate top-left point for diagram //first, calculate the centroid of the label (accounts for PAL creating //rotated labels when we do not want to draw the diagrams rotated) double centerX = 0; double centerY = 0; for ( int i = 0; i < 4; ++i ) { centerX += label->getX( i ); centerY += label->getY( i ); } QgsPointXY outPt( centerX / 4.0, centerY / 4.0 ); //then, calculate the top left point for the diagram with this center position QgsPointXY centerPt = xform.transform( outPt.x() - label->getWidth() / 2, outPt.y() - label->getHeight() / 2 ); mSettings.renderer()->renderDiagram( feature, context, centerPt.toQPointF(), mSettings.dataDefinedProperties() ); //insert into label search tree to manipulate position interactively mEngine->results()->mLabelSearchTree->insertLabel( label, label->getFeaturePart()->featureId(), mLayerId, QString(), QFont(), true, false ); }
void QgsVectorLayerFeatureIterator::useChangedAttributeFeature( QgsFeatureId fid, const QgsGeometry& geom, QgsFeature& f ) { f.setFeatureId( fid ); f.setValid( true ); f.setFields( &L->mUpdatedFields ); if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) { f.setGeometry( geom ); // simplify the edited geometry using its simplifier configured if ( mEditGeometrySimplifier ) { QgsGeometry* geometry = f.geometry(); QGis::GeometryType geometryType = geometry->type(); if ( geometryType == QGis::Line || geometryType == QGis::Polygon ) mEditGeometrySimplifier->simplifyGeometry( geometry ); } } bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ); if ( !subsetAttrs || ( subsetAttrs && mRequest.subsetOfAttributes().count() > 0 ) ) { // retrieve attributes from provider QgsFeature tmp; //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes ); QgsFeatureRequest request; request.setFilterFid( fid ).setFlags( QgsFeatureRequest::NoGeometry ); if ( subsetAttrs ) { request.setSubsetOfAttributes( mProviderRequest.subsetOfAttributes() ); } QgsFeatureIterator fi = L->dataProvider()->getFeatures( request ); if ( fi.nextFeature( tmp ) ) { updateChangedAttributes( tmp ); f.setAttributes( tmp.attributes() ); } } if ( !mFetchJoinInfo.isEmpty() ) addJoinedAttributes( f ); }
void QgsOfflineEditing::applyFeaturesAdded( QgsVectorLayer* offlineLayer, QgsVectorLayer* remoteLayer, sqlite3* db, int layerId ) { QString sql = QString( "SELECT \"fid\" FROM 'log_added_features' WHERE \"layer_id\" = %1" ).arg( layerId ); QList<int> newFeatureIds = sqlQueryInts( db, sql ); // get new features from offline layer QgsFeatureList features; for ( int i = 0; i < newFeatureIds.size(); i++ ) { QgsFeature feature; if ( offlineLayer->getFeatures( QgsFeatureRequest().setFilterFid( newFeatureIds.at( i ) ) ).nextFeature( feature ) ) { features << feature; } } // copy features to remote layer emit progressModeSet( QgsOfflineEditing::AddFeatures, features.size() ); int i = 1; int newAttrsCount = remoteLayer->pendingFields().count(); for ( QgsFeatureList::iterator it = features.begin(); it != features.end(); ++it ) { QgsFeature f = *it; // NOTE: Spatialite provider ignores position of geometry column // restore gap in QgsAttributeMap if geometry column is not last (WORKAROUND) QMap<int, int> attrLookup = attributeLookup( offlineLayer, remoteLayer ); QgsAttributes newAttrs( newAttrsCount ); QgsAttributes attrs = f.attributes(); for ( int it = 0; it < attrs.count(); ++it ) { newAttrs[ attrLookup[ it ] ] = attrs[ it ]; } f.setAttributes( newAttrs ); remoteLayer->addFeature( f, false ); emit progressUpdated( i++ ); } }
void QgsOverlayAnalyzer::intersectFeature( QgsFeature& f, QgsVectorFileWriter* vfw, QgsVectorLayer* vl, QgsSpatialIndex* index ) { if ( !f.hasGeometry() ) { return; } QgsGeometry featureGeometry = f.geometry(); QgsGeometry intersectGeometry; QgsFeature overlayFeature; QList<QgsFeatureId> intersects; intersects = index->intersects( featureGeometry.boundingBox() ); QList<QgsFeatureId>::const_iterator it = intersects.constBegin(); QgsFeature outFeature; for ( ; it != intersects.constEnd(); ++it ) { if ( !vl->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( overlayFeature ) ) { continue; } if ( featureGeometry.intersects( overlayFeature.geometry() ) ) { intersectGeometry = featureGeometry.intersection( overlayFeature.geometry() ); outFeature.setGeometry( intersectGeometry ); QgsAttributes attributesA = f.attributes(); QgsAttributes attributesB = overlayFeature.attributes(); combineAttributeMaps( attributesA, attributesB ); outFeature.setAttributes( attributesA ); //add it to vector file writer if ( vfw ) { vfw->addFeature( outFeature ); } } } }
void QgsGeometryAnalyzer::centroidFeature( QgsFeature& f, QgsVectorFileWriter* vfw ) { QgsGeometry* featureGeometry = f.geometry(); QgsGeometry* tmpGeometry = 0; if ( !featureGeometry ) { return; } tmpGeometry = featureGeometry->centroid(); QgsFeature newFeature; newFeature.setGeometry( tmpGeometry ); newFeature.setAttributes( f.attributes() ); //add it to vector file writer if ( vfw ) { vfw->addFeature( newFeature ); } }
void QgsGeometryAnalyzer::simplifyFeature( QgsFeature& f, QgsVectorFileWriter* vfw, double tolerance ) { if ( !f.hasGeometry() ) { return; } QgsGeometry featureGeometry = f.geometry(); // simplify feature QgsGeometry tmpGeometry = featureGeometry.simplify( tolerance ); QgsFeature newFeature; newFeature.setGeometry( tmpGeometry ); newFeature.setAttributes( f.attributes() ); //add it to vector file writer if ( vfw ) { vfw->addFeature( newFeature ); } }
void QgsVectorLayerEditBuffer::updateChangedAttributes( QgsFeature &f ) { QgsAttributes attrs = f.attributes(); // remove all attributes that will disappear - from higher indices to lower for ( int idx = mDeletedAttributeIds.count() - 1; idx >= 0; --idx ) { attrs.remove( mDeletedAttributeIds[idx] ); } // adjust size to accommodate added attributes attrs.resize( attrs.count() + mAddedAttributes.count() ); // update changed attributes if ( mChangedAttributeValues.contains( f.id() ) ) { const QgsAttributeMap &map = mChangedAttributeValues[f.id()]; for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it ) attrs[it.key()] = it.value(); } f.setAttributes( attrs ); }
void QgsOverlayAnalyzer::intersectFeature( QgsFeature &f, QgsVectorFileWriter *vfw, QgsVectorLayer *vl, QgsSpatialIndex *index ) { if ( !f.hasGeometry() ) { return; } QgsGeometry featureGeometry = f.geometry(); QgsGeometry intersectGeometry; QgsFeature overlayFeature; QList<QgsFeatureId> intersects = index->intersects( featureGeometry.boundingBox() ); QgsFeatureRequest req = QgsFeatureRequest().setFilterFids( intersects.toSet() ); QgsFeatureIterator intersectIt = vl->getFeatures( req ); QgsFeature outFeature; while ( intersectIt.nextFeature( overlayFeature ) ) { if ( featureGeometry.intersects( overlayFeature.geometry() ) ) { intersectGeometry = featureGeometry.intersection( overlayFeature.geometry() ); outFeature.setGeometry( intersectGeometry ); QgsAttributes attributesA = f.attributes(); QgsAttributes attributesB = overlayFeature.attributes(); combineAttributeMaps( attributesA, attributesB ); outFeature.setAttributes( attributesA ); //add it to vector file writer if ( vfw ) { vfw->addFeature( outFeature ); } } } }
QVariantMap QgsSplitWithLinesAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); if ( !source ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) ); std::unique_ptr< QgsFeatureSource > linesSource( parameterAsSource( parameters, QStringLiteral( "LINES" ), context ) ); if ( !linesSource ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "LINES" ) ) ); bool sameLayer = parameters.value( QStringLiteral( "INPUT" ) ) == parameters.value( QStringLiteral( "LINES" ) ); QString dest; std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), QgsWkbTypes::multiType( source->wkbType() ), source->sourceCrs() ) ); if ( !sink ) throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); QgsSpatialIndex spatialIndex; QMap< QgsFeatureId, QgsGeometry > splitGeoms; QgsFeatureRequest request; request.setSubsetOfAttributes( QgsAttributeList() ); request.setDestinationCrs( source->sourceCrs(), context.transformContext() ); QgsFeatureIterator splitLines = linesSource->getFeatures( request ); QgsFeature aSplitFeature; while ( splitLines.nextFeature( aSplitFeature ) ) { if ( feedback->isCanceled() ) { break; } splitGeoms.insert( aSplitFeature.id(), aSplitFeature.geometry() ); spatialIndex.addFeature( aSplitFeature ); } QgsFeature outFeat; QgsFeatureIterator features = source->getFeatures(); double step = source->featureCount() > 0 ? 100.0 / source->featureCount() : 1; int i = 0; QgsFeature inFeatureA; while ( features.nextFeature( inFeatureA ) ) { i++; if ( feedback->isCanceled() ) { break; } if ( !inFeatureA.hasGeometry() ) { sink->addFeature( inFeatureA, QgsFeatureSink::FastInsert ); continue; } QgsGeometry inGeom = inFeatureA.geometry(); outFeat.setAttributes( inFeatureA.attributes() ); QVector< QgsGeometry > inGeoms = inGeom.asGeometryCollection(); const QgsFeatureIds lines = spatialIndex.intersects( inGeom.boundingBox() ).toSet(); if ( !lines.empty() ) // has intersection of bounding boxes { QVector< QgsGeometry > splittingLines; // use prepared geometries for faster intersection tests std::unique_ptr< QgsGeometryEngine > engine; for ( QgsFeatureId line : lines ) { // check if trying to self-intersect if ( sameLayer && inFeatureA.id() == line ) continue; QgsGeometry splitGeom = splitGeoms.value( line ); if ( !engine ) { engine.reset( QgsGeometry::createGeometryEngine( inGeom.constGet() ) ); engine->prepareGeometry(); } if ( engine->intersects( splitGeom.constGet() ) ) { QVector< QgsGeometry > splitGeomParts = splitGeom.asGeometryCollection(); splittingLines.append( splitGeomParts ); } } if ( !splittingLines.empty() ) { for ( const QgsGeometry &splitGeom : qgis::as_const( splittingLines ) ) { QVector<QgsPointXY> splitterPList; QVector< QgsGeometry > outGeoms; // use prepared geometries for faster intersection tests std::unique_ptr< QgsGeometryEngine > splitGeomEngine( QgsGeometry::createGeometryEngine( splitGeom.constGet() ) ); splitGeomEngine->prepareGeometry(); while ( !inGeoms.empty() ) { if ( feedback->isCanceled() ) { break; } QgsGeometry inGeom = inGeoms.takeFirst(); if ( !inGeom ) continue; if ( splitGeomEngine->intersects( inGeom.constGet() ) ) { QgsGeometry before = inGeom; if ( splitterPList.empty() ) { const QgsCoordinateSequence sequence = splitGeom.constGet()->coordinateSequence(); for ( const QgsRingSequence &part : sequence ) { for ( const QgsPointSequence &ring : part ) { for ( const QgsPoint &pt : ring ) { splitterPList << QgsPointXY( pt ); } } } } QVector< QgsGeometry > newGeometries; QVector<QgsPointXY> topologyTestPoints; QgsGeometry::OperationResult result = inGeom.splitGeometry( splitterPList, newGeometries, false, topologyTestPoints ); // splitGeometry: If there are several intersections // between geometry and splitLine, only the first one is considered. if ( result == QgsGeometry::Success ) // split occurred { if ( inGeom.isGeosEqual( before ) ) { // bug in splitGeometry: sometimes it returns 0 but // the geometry is unchanged outGeoms.append( inGeom ); } else { inGeoms.append( inGeom ); inGeoms.append( newGeometries ); } } else { outGeoms.append( inGeom ); } } else { outGeoms.append( inGeom ); } } inGeoms = outGeoms; } } } QVector< QgsGeometry > parts; for ( const QgsGeometry &aGeom : qgis::as_const( inGeoms ) ) { if ( feedback->isCanceled() ) { break; } bool passed = true; if ( QgsWkbTypes::geometryType( aGeom.wkbType() ) == QgsWkbTypes::LineGeometry ) { int numPoints = aGeom.constGet()->nCoordinates(); if ( numPoints <= 2 ) { if ( numPoints == 2 ) passed = !static_cast< const QgsCurve * >( aGeom.constGet() )->isClosed(); // tests if vertex 0 = vertex 1 else passed = false; // sometimes splitting results in lines of zero length } } if ( passed ) parts.append( aGeom ); } for ( const QgsGeometry &g : parts ) { outFeat.setGeometry( g ); sink->addFeature( outFeat, QgsFeatureSink::FastInsert ); } feedback->setProgress( i * step ); } QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), dest ); return outputs; }
QVariantMap QgsClipAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { std::unique_ptr< QgsFeatureSource > featureSource( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); if ( !featureSource ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) ); std::unique_ptr< QgsFeatureSource > maskSource( parameterAsSource( parameters, QStringLiteral( "OVERLAY" ), context ) ); if ( !maskSource ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "OVERLAY" ) ) ); QString dest; QgsWkbTypes::GeometryType sinkType = QgsWkbTypes::geometryType( featureSource->wkbType() ); std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, featureSource->fields(), QgsWkbTypes::multiType( featureSource->wkbType() ), featureSource->sourceCrs() ) ); if ( !sink ) throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); // first build up a list of clip geometries QVector< QgsGeometry > clipGeoms; QgsFeatureIterator it = maskSource->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QList< int >() ).setDestinationCrs( featureSource->sourceCrs(), context.transformContext() ) ); QgsFeature f; while ( it.nextFeature( f ) ) { if ( f.hasGeometry() ) clipGeoms << f.geometry(); } QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), dest ); if ( clipGeoms.isEmpty() ) return outputs; // are we clipping against a single feature? if so, we can show finer progress reports bool singleClipFeature = false; QgsGeometry combinedClipGeom; if ( clipGeoms.length() > 1 ) { combinedClipGeom = QgsGeometry::unaryUnion( clipGeoms ); if ( combinedClipGeom.isEmpty() ) { throw QgsProcessingException( QObject::tr( "Could not create the combined clip geometry: %1" ).arg( combinedClipGeom.lastError() ) ); } singleClipFeature = false; } else { combinedClipGeom = clipGeoms.at( 0 ); singleClipFeature = true; } // use prepared geometries for faster intersection tests std::unique_ptr< QgsGeometryEngine > engine( QgsGeometry::createGeometryEngine( combinedClipGeom.constGet() ) ); engine->prepareGeometry(); QgsFeatureIds testedFeatureIds; int i = -1; Q_FOREACH ( const QgsGeometry &clipGeom, clipGeoms ) { i++; if ( feedback->isCanceled() ) { break; } QgsFeatureIterator inputIt = featureSource->getFeatures( QgsFeatureRequest().setFilterRect( clipGeom.boundingBox() ) ); QgsFeatureList inputFeatures; QgsFeature f; while ( inputIt.nextFeature( f ) ) inputFeatures << f; if ( inputFeatures.isEmpty() ) continue; double step = 0; if ( singleClipFeature ) step = 100.0 / inputFeatures.length(); int current = 0; Q_FOREACH ( const QgsFeature &inputFeature, inputFeatures ) { if ( feedback->isCanceled() ) { break; } if ( !inputFeature.hasGeometry() ) continue; if ( testedFeatureIds.contains( inputFeature.id() ) ) { // don't retest a feature we have already checked continue; } testedFeatureIds.insert( inputFeature.id() ); if ( !engine->intersects( inputFeature.geometry().constGet() ) ) continue; QgsGeometry newGeometry; if ( !engine->contains( inputFeature.geometry().constGet() ) ) { QgsGeometry currentGeometry = inputFeature.geometry(); newGeometry = combinedClipGeom.intersection( currentGeometry ); if ( newGeometry.wkbType() == QgsWkbTypes::Unknown || QgsWkbTypes::flatType( newGeometry.wkbType() ) == QgsWkbTypes::GeometryCollection ) { QgsGeometry intCom = inputFeature.geometry().combine( newGeometry ); QgsGeometry intSym = inputFeature.geometry().symDifference( newGeometry ); newGeometry = intCom.difference( intSym ); } } else { // clip geometry totally contains feature geometry, so no need to perform intersection newGeometry = inputFeature.geometry(); } if ( !QgsOverlayUtils::sanitizeIntersectionResult( newGeometry, sinkType ) ) continue; QgsFeature outputFeature; outputFeature.setGeometry( newGeometry ); outputFeature.setAttributes( inputFeature.attributes() ); sink->addFeature( outputFeature, QgsFeatureSink::FastInsert ); if ( singleClipFeature ) feedback->setProgress( current * step ); } if ( !singleClipFeature ) { // coarse progress report for multiple clip geometries feedback->setProgress( 100.0 * static_cast< double >( i ) / clipGeoms.length() ); } }
bool QgsGeometryAnalyzer::convexHull( QgsVectorLayer* layer, const QString& shapefileName, bool onlySelectedFeatures, int uniqueIdField, QProgressDialog* p ) { if ( !layer ) { return false; } QgsVectorDataProvider* dp = layer->dataProvider(); if ( !dp ) { return false; } bool useField = false; if ( uniqueIdField == -1 ) { uniqueIdField = 0; } else { useField = true; } QgsFields fields; fields.append( QgsField( QStringLiteral( "UID" ), QVariant::String ) ); fields.append( QgsField( QStringLiteral( "AREA" ), QVariant::Double ) ); fields.append( QgsField( QStringLiteral( "PERIM" ), QVariant::Double ) ); QgsWkbTypes::Type outputType = QgsWkbTypes::Polygon; QgsCoordinateReferenceSystem crs = layer->crs(); QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), fields, outputType, crs ); QgsFeature currentFeature; QgsGeometry dissolveGeometry; //dissolve geometry QMultiMap<QString, QgsFeatureId> map; if ( onlySelectedFeatures ) { //use QgsVectorLayer::featureAtId const QgsFeatureIds selection = layer->selectedFeaturesIds(); QgsFeatureIds::const_iterator it = selection.constBegin(); for ( ; it != selection.constEnd(); ++it ) { #if 0 if ( p ) { p->setValue( processedFeatures ); } if ( p && p->wasCanceled() ) { // break; // it may be better to do something else here? return false; } #endif if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) ) { continue; } map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() ); } } else { QgsFeatureIterator fit = layer->getFeatures(); while ( fit.nextFeature( currentFeature ) ) { #if 0 if ( p ) { p->setValue( processedFeatures ); } if ( p && p->wasCanceled() ) { // break; // it may be better to do something else here? return false; } #endif map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() ); } } QMultiMap<QString, QgsFeatureId>::const_iterator jt = map.constBegin(); while ( jt != map.constEnd() ) { QString currentKey = jt.key(); int processedFeatures = 0; //take only selection if ( onlySelectedFeatures ) { //use QgsVectorLayer::featureAtId const QgsFeatureIds selection = layer->selectedFeaturesIds(); if ( p ) { p->setMaximum( selection.size() ); } processedFeatures = 0; while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) ) { if ( p && p->wasCanceled() ) { break; } if ( selection.contains( jt.value() ) ) { if ( p ) { p->setValue( processedFeatures ); } if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) ) { continue; } convexFeature( currentFeature, processedFeatures, dissolveGeometry ); ++processedFeatures; } ++jt; } QList<double> values; if ( dissolveGeometry.isEmpty() ) { QgsDebugMsg( "no dissolved geometry - should not happen" ); return false; } dissolveGeometry = dissolveGeometry.convexHull(); values = simpleMeasure( dissolveGeometry ); QgsAttributes attributes( 3 ); attributes[0] = QVariant( currentKey ); attributes[1] = values.at( 0 ); attributes[2] = values.at( 1 ); QgsFeature dissolveFeature; dissolveFeature.setAttributes( attributes ); dissolveFeature.setGeometry( dissolveGeometry ); vWriter.addFeature( dissolveFeature ); } //take all features else { int featureCount = layer->featureCount(); if ( p ) { p->setMaximum( featureCount ); } processedFeatures = 0; while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) ) { if ( p ) { p->setValue( processedFeatures ); } if ( p && p->wasCanceled() ) { break; } if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) ) { continue; } convexFeature( currentFeature, processedFeatures, dissolveGeometry ); ++processedFeatures; ++jt; } QList<double> values; if ( dissolveGeometry.isEmpty() ) { QgsDebugMsg( "no dissolved geometry - should not happen" ); return false; } dissolveGeometry = dissolveGeometry.convexHull(); // values = simpleMeasure( tmpGeometry ); values = simpleMeasure( dissolveGeometry ); QgsAttributes attributes; attributes[0] = QVariant( currentKey ); attributes[1] = QVariant( values[ 0 ] ); attributes[2] = QVariant( values[ 1 ] ); QgsFeature dissolveFeature; dissolveFeature.setAttributes( attributes ); dissolveFeature.setGeometry( dissolveGeometry ); vWriter.addFeature( dissolveFeature ); } } return true; }
bool QgsPostgresFeatureIterator::nextFeature( QgsFeature& feature ) { feature.setValid( false ); if ( mClosed ) return false; #if 0 // featureAtId used to have some special checks - necessary? if ( !mUseQueue ) { QgsPostgresResult queryResult = P->mConnectionRO->PQexec( QString( "FETCH FORWARD 1 FROM %1" ).arg( mCursorName ) ); int rows = queryResult.PQntuples(); if ( rows == 0 ) { QgsMessageLog::logMessage( tr( "feature %1 not found" ).arg( featureId ), tr( "PostGIS" ) ); P->mConnectionRO->closeCursor( cursorName ); return false; } else if ( rows != 1 ) { QgsMessageLog::logMessage( tr( "found %1 features instead of just one." ).arg( rows ), tr( "PostGIS" ) ); } bool gotit = getFeature( queryResult, 0, feature ); feature.setValid( gotit ); feature.setFields( &P->mAttributeFields ); // allow name-based attribute lookups return gotit; } #endif if ( mFeatureQueue.empty() ) { QString fetch = QString( "FETCH FORWARD %1 FROM %2" ).arg( mFeatureQueueSize ).arg( mCursorName ); QgsDebugMsgLevel( QString( "fetching %1 features." ).arg( mFeatureQueueSize ), 4 ); if ( P->mConnectionRO->PQsendQuery( fetch ) == 0 ) // fetch features asynchronously { QgsMessageLog::logMessage( QObject::tr( "Fetching from cursor %1 failed\nDatabase error: %2" ).arg( mCursorName ).arg( P->mConnectionRO->PQerrorMessage() ), QObject::tr( "PostGIS" ) ); } QgsPostgresResult queryResult; for ( ;; ) { queryResult = P->mConnectionRO->PQgetResult(); if ( !queryResult.result() ) break; if ( queryResult.PQresultStatus() != PGRES_TUPLES_OK ) { QgsMessageLog::logMessage( QObject::tr( "Fetching from cursor %1 failed\nDatabase error: %2" ).arg( mCursorName ).arg( P->mConnectionRO->PQerrorMessage() ), QObject::tr( "PostGIS" ) ); break; } int rows = queryResult.PQntuples(); if ( rows == 0 ) continue; for ( int row = 0; row < rows; row++ ) { mFeatureQueue.enqueue( QgsFeature() ); getFeature( queryResult, row, mFeatureQueue.back() ); } // for each row in queue } } if ( mFeatureQueue.empty() ) { QgsDebugMsg( QString( "Finished after %1 features" ).arg( mFetched ) ); close(); if ( P->mFeaturesCounted < mFetched ) { QgsDebugMsg( QString( "feature count adjusted from %1 to %2" ).arg( P->mFeaturesCounted ).arg( mFetched ) ); P->mFeaturesCounted = mFetched; } return false; } // Now return the next feature from the queue if ( mRequest.flags() & QgsFeatureRequest::NoGeometry ) { feature.setGeometryAndOwnership( 0, 0 ); } else { QgsGeometry* featureGeom = mFeatureQueue.front().geometryAndOwnership(); feature.setGeometry( featureGeom ); } feature.setFeatureId( mFeatureQueue.front().id() ); feature.setAttributes( mFeatureQueue.front().attributes() ); mFeatureQueue.dequeue(); mFetched++; feature.setValid( true ); feature.setFields( &P->mAttributeFields ); // allow name-based attribute lookups return true; }
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; }
QVariantMap QgsShortestPathPointToPointAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { loadCommonParams( parameters, context, feedback ); QgsFields fields; fields.append( QgsField( QStringLiteral( "start" ), QVariant::String ) ); fields.append( QgsField( QStringLiteral( "end" ), QVariant::String ) ); fields.append( QgsField( QStringLiteral( "cost" ), QVariant::Double ) ); QString dest; std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, QgsWkbTypes::LineString, mNetwork->sourceCrs() ) ); if ( !sink ) throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); QgsPointXY startPoint = parameterAsPoint( parameters, QStringLiteral( "START_POINT" ), context, mNetwork->sourceCrs() ); QgsPointXY endPoint = parameterAsPoint( parameters, QStringLiteral( "END_POINT" ), context, mNetwork->sourceCrs() ); feedback->pushInfo( QObject::tr( "Building graph…" ) ); QVector< QgsPointXY > points; points << startPoint << endPoint; QVector< QgsPointXY > snappedPoints; mDirector->makeGraph( mBuilder.get(), points, snappedPoints, feedback ); feedback->pushInfo( QObject::tr( "Calculating shortest path…" ) ); QgsGraph *graph = mBuilder->graph(); int idxStart = graph->findVertex( snappedPoints[0] ); int idxEnd = graph->findVertex( snappedPoints[1] ); QVector< int > tree; QVector< double > costs; QgsGraphAnalyzer::dijkstra( graph, idxStart, 0, &tree, &costs ); if ( tree.at( idxEnd ) == -1 ) { throw QgsProcessingException( QObject::tr( "There is no route from start point to end point." ) ); } QVector<QgsPointXY> route; route.push_front( graph->vertex( idxEnd ).point() ); double cost = costs.at( idxEnd ); while ( idxEnd != idxStart ) { idxEnd = graph->edge( tree.at( idxEnd ) ).fromVertex(); route.push_front( graph->vertex( idxEnd ).point() ); } feedback->pushInfo( QObject::tr( "Writing results…" ) ); QgsGeometry geom = QgsGeometry::fromPolylineXY( route ); QgsFeature feat; feat.setFields( fields ); QgsAttributes attributes; attributes << startPoint.toString() << endPoint.toString() << cost / mMultiplier; feat.setGeometry( geom ); feat.setAttributes( attributes ); sink->addFeature( feat, QgsFeatureSink::FastInsert ); QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), dest ); outputs.insert( QStringLiteral( "TRAVEL_COST" ), cost / mMultiplier ); return outputs; }
void QgsGeometryTypeCheck::fixError( QgsGeometryCheckError* error, int method, int /*mergeAttributeIndex*/, Changes &changes ) const { QgsFeature feature; if ( !mFeaturePool->get( error->featureId(), feature ) ) { error->setObsolete(); return; } QgsGeometry featureGeom = feature.geometry(); QgsAbstractGeometry* geom = featureGeom.geometry(); // Check if error still applies QgsWkbTypes::Type type = QgsWkbTypes::flatType( geom->wkbType() ); if (( mAllowedTypes & ( 1 << type ) ) != 0 ) { error->setObsolete(); return; } // Fix with selected method if ( method == NoChange ) { error->setFixed( method ); } else if ( method == Convert ) { // Check if corresponding single type is allowed if ( QgsWkbTypes::isMultiType( type ) && (( 1 << QgsWkbTypes::singleType( type ) ) & mAllowedTypes ) != 0 ) { // Explode multi-type feature into single-type features for ( int iPart = 1, nParts = geom->partCount(); iPart < nParts; ++iPart ) { QgsFeature newFeature; newFeature.setAttributes( feature.attributes() ); newFeature.setGeometry( QgsGeometry( QgsGeometryCheckerUtils::getGeomPart( geom, iPart )->clone() ) ); mFeaturePool->addFeature( newFeature ); changes[newFeature.id()].append( Change( ChangeFeature, ChangeAdded ) ); } // Recycle feature for part 0 feature.setGeometry( QgsGeometry( QgsGeometryCheckerUtils::getGeomPart( geom, 0 )->clone() ) ); mFeaturePool->updateFeature( feature ); changes[feature.id()].append( Change( ChangeFeature, ChangeChanged ) ); } // Check if corresponding multi type is allowed else if ( QgsWkbTypes::isSingleType( type ) && (( 1 << QgsWkbTypes::multiType( type ) ) & mAllowedTypes ) != 0 ) { QgsGeometryCollection* geomCollection = nullptr; switch ( QgsWkbTypes::multiType( type ) ) { case QgsWkbTypes::MultiPoint: { geomCollection = new QgsMultiPointV2(); break; } case QgsWkbTypes::MultiLineString: { geomCollection = new QgsMultiLineString(); break; } case QgsWkbTypes::MultiPolygon: { geomCollection = new QgsMultiPolygonV2(); break; } case QgsWkbTypes::MultiCurve: { geomCollection = new QgsMultiCurve(); break; } case QgsWkbTypes::MultiSurface: { geomCollection = new QgsMultiSurface(); break; } default: break; } if ( !geomCollection ) { error->setFixFailed( tr( "Unknown geometry type" ) ); } else { geomCollection->addGeometry( geom->clone() ); feature.setGeometry( QgsGeometry( geomCollection ) ); mFeaturePool->updateFeature( feature ); changes[feature.id()].append( Change( ChangeFeature, ChangeChanged ) ); } } // Delete feature else { mFeaturePool->deleteFeature( feature ); changes[error->featureId()].append( Change( ChangeFeature, ChangeRemoved ) ); } error->setFixed( method ); } else if ( method == Delete ) { mFeaturePool->deleteFeature( feature ); error->setFixed( method ); changes[error->featureId()].append( Change( ChangeFeature, ChangeRemoved ) ); } else { error->setFixFailed( tr( "Unknown method" ) ); } }
bool QgsGeometryAnalyzer::extent( QgsVectorLayer* layer, const QString& shapefileName, bool onlySelectedFeatures, QProgressDialog * ) { if ( !layer ) { return false; } QgsVectorDataProvider* dp = layer->dataProvider(); if ( !dp ) { return false; } QgsWkbTypes::Type outputType = QgsWkbTypes::Polygon; QgsCoordinateReferenceSystem crs = layer->crs(); QgsFields fields; fields.append( QgsField( QStringLiteral( "MINX" ), QVariant::Double ) ); fields.append( QgsField( QStringLiteral( "MINY" ), QVariant::Double ) ); fields.append( QgsField( QStringLiteral( "MAXX" ), QVariant::Double ) ); fields.append( QgsField( QStringLiteral( "MAXY" ), QVariant::Double ) ); fields.append( QgsField( QStringLiteral( "CNTX" ), QVariant::Double ) ); fields.append( QgsField( QStringLiteral( "CNTY" ), QVariant::Double ) ); fields.append( QgsField( QStringLiteral( "AREA" ), QVariant::Double ) ); fields.append( QgsField( QStringLiteral( "PERIM" ), QVariant::Double ) ); fields.append( QgsField( QStringLiteral( "HEIGHT" ), QVariant::Double ) ); fields.append( QgsField( QStringLiteral( "WIDTH" ), QVariant::Double ) ); QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), fields, outputType, crs ); QgsRectangle rect; if ( onlySelectedFeatures ) // take only selection { rect = layer->boundingBoxOfSelected(); } else { rect = layer->extent(); } double minx = rect.xMinimum(); double miny = rect.yMinimum(); double maxx = rect.xMaximum(); double maxy = rect.yMaximum(); double height = rect.height(); double width = rect.width(); double cntx = minx + ( width / 2.0 ); double cnty = miny + ( height / 2.0 ); double area = width * height; double perim = ( 2 * width ) + ( 2 * height ); QgsFeature feat; QgsAttributes attrs( 10 ); attrs[0] = QVariant( minx ); attrs[1] = QVariant( miny ); attrs[2] = QVariant( maxx ); attrs[3] = QVariant( maxy ); attrs[4] = QVariant( cntx ); attrs[5] = QVariant( cnty ); attrs[6] = QVariant( area ); attrs[7] = QVariant( perim ); attrs[8] = QVariant( height ); attrs[9] = QVariant( width ); feat.setAttributes( attrs ); feat.setGeometry( QgsGeometry::fromRect( rect ) ); vWriter.addFeature( feat ); return true; }
QVariantMap QgsLineIntersectionAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { std::unique_ptr< QgsFeatureSource > sourceA( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); if ( !sourceA ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) ); std::unique_ptr< QgsFeatureSource > sourceB( parameterAsSource( parameters, QStringLiteral( "INTERSECT" ), context ) ); if ( !sourceB ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INTERSECT" ) ) ); const QStringList fieldsA = parameterAsFields( parameters, QStringLiteral( "INPUT_FIELDS" ), context ); const QStringList fieldsB = parameterAsFields( parameters, QStringLiteral( "INTERSECT_FIELDS" ), context ); QgsAttributeList fieldIndicesA = QgsProcessingUtils::fieldNamesToIndices( fieldsA, sourceA->fields() ); QgsAttributeList fieldIndicesB = QgsProcessingUtils::fieldNamesToIndices( fieldsB, sourceB->fields() ); QString intersectFieldsPrefix = parameterAsString( parameters, QStringLiteral( "INTERSECT_FIELDS_PREFIX" ), context ); QgsFields outFields = QgsProcessingUtils::combineFields( QgsProcessingUtils::indicesToFields( fieldIndicesA, sourceA->fields() ), QgsProcessingUtils::indicesToFields( fieldIndicesB, sourceB->fields() ), intersectFieldsPrefix ); QString dest; std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, outFields, QgsWkbTypes::Point, sourceA->sourceCrs(), QgsFeatureSink::RegeneratePrimaryKey ) ); if ( !sink ) throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); QgsSpatialIndex spatialIndex( sourceB->getFeatures( QgsFeatureRequest().setNoAttributes().setDestinationCrs( sourceA->sourceCrs(), context.transformContext() ) ), feedback ); QgsFeature outFeature; QgsFeatureIterator features = sourceA->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( fieldIndicesA ) ); double step = sourceA->featureCount() > 0 ? 100.0 / sourceA->featureCount() : 1; int i = 0; QgsFeature inFeatureA; while ( features.nextFeature( inFeatureA ) ) { i++; if ( feedback->isCanceled() ) { break; } if ( !inFeatureA.hasGeometry() ) continue; QgsGeometry inGeom = inFeatureA.geometry(); QgsFeatureIds lines = spatialIndex.intersects( inGeom.boundingBox() ).toSet(); if ( !lines.empty() ) { // use prepared geometries for faster intersection tests std::unique_ptr< QgsGeometryEngine > engine( QgsGeometry::createGeometryEngine( inGeom.constGet() ) ); engine->prepareGeometry(); QgsFeatureRequest request = QgsFeatureRequest().setFilterFids( lines ); request.setDestinationCrs( sourceA->sourceCrs(), context.transformContext() ); request.setSubsetOfAttributes( fieldIndicesB ); QgsFeature inFeatureB; QgsFeatureIterator featuresB = sourceB->getFeatures( request ); while ( featuresB.nextFeature( inFeatureB ) ) { if ( feedback->isCanceled() ) { break; } QgsGeometry tmpGeom = inFeatureB.geometry(); if ( engine->intersects( tmpGeom.constGet() ) ) { QgsMultiPointXY points; QgsGeometry intersectGeom = inGeom.intersection( tmpGeom ); QgsAttributes outAttributes; for ( int a : qgis::as_const( fieldIndicesA ) ) { outAttributes.append( inFeatureA.attribute( a ) ); } for ( int b : qgis::as_const( fieldIndicesB ) ) { outAttributes.append( inFeatureB.attribute( b ) ); } if ( QgsWkbTypes::flatType( intersectGeom.wkbType() ) == QgsWkbTypes::GeometryCollection ) { const QVector<QgsGeometry> geomCollection = intersectGeom.asGeometryCollection(); for ( const QgsGeometry &part : geomCollection ) { if ( part.type() == QgsWkbTypes::PointGeometry ) { if ( part.isMultipart() ) { points = part.asMultiPoint(); } else { points.append( part.asPoint() ); } } } } else if ( intersectGeom.type() == QgsWkbTypes::PointGeometry ) { if ( intersectGeom.isMultipart() ) { points = intersectGeom.asMultiPoint(); } else { points.append( intersectGeom.asPoint() ); } } for ( const QgsPointXY &j : qgis::as_const( points ) ) { outFeature.setGeometry( QgsGeometry::fromPointXY( j ) ); outFeature.setAttributes( outAttributes ); sink->addFeature( outFeature, QgsFeatureSink::FastInsert ); } } } } feedback->setProgress( i * step ); } QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), dest ); return outputs; }
bool QgsGeometryAnalyzer::dissolve( QgsVectorLayer* layer, const QString& shapefileName, bool onlySelectedFeatures, int uniqueIdField, QProgressDialog* p ) { if ( !layer ) { return false; } QgsVectorDataProvider* dp = layer->dataProvider(); if ( !dp ) { return false; } bool useField = false; if ( uniqueIdField == -1 ) { uniqueIdField = 0; } else { useField = true; } QgsWkbTypes::Type outputType = dp->wkbType(); QgsCoordinateReferenceSystem crs = layer->crs(); QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->fields(), outputType, crs ); QgsFeature currentFeature; QMultiMap<QString, QgsFeatureId> map; if ( onlySelectedFeatures ) { //use QgsVectorLayer::featureAtId const QgsFeatureIds selection = layer->selectedFeaturesIds(); QgsFeatureIds::const_iterator it = selection.constBegin(); for ( ; it != selection.constEnd(); ++it ) { if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) ) { continue; } map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() ); } } else { QgsFeatureIterator fit = layer->getFeatures(); while ( fit.nextFeature( currentFeature ) ) { map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() ); } } QgsGeometry dissolveGeometry; //dissolve geometry QMultiMap<QString, QgsFeatureId>::const_iterator jt = map.constBegin(); QgsFeature outputFeature; while ( jt != map.constEnd() ) { QString currentKey = jt.key(); int processedFeatures = 0; bool first = true; //take only selection if ( onlySelectedFeatures ) { //use QgsVectorLayer::featureAtId const QgsFeatureIds selection = layer->selectedFeaturesIds(); if ( p ) { p->setMaximum( selection.size() ); } while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) ) { if ( p && p->wasCanceled() ) { break; } if ( selection.contains( jt.value() ) ) { if ( p ) { p->setValue( processedFeatures ); } if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) ) { continue; } if ( first ) { outputFeature.setAttributes( currentFeature.attributes() ); first = false; } dissolveGeometry = dissolveFeature( currentFeature, dissolveGeometry ); ++processedFeatures; } ++jt; } } //take all features else { int featureCount = layer->featureCount(); if ( p ) { p->setMaximum( featureCount ); } while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) ) { if ( p ) { p->setValue( processedFeatures ); } if ( p && p->wasCanceled() ) { break; } if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) ) { continue; } { outputFeature.setAttributes( currentFeature.attributes() ); first = false; } dissolveGeometry = dissolveFeature( currentFeature, dissolveGeometry ); ++processedFeatures; ++jt; } } outputFeature.setGeometry( dissolveGeometry ); vWriter.addFeature( outputFeature ); } return true; }
void QgsMapToolFillRing::cadCanvasReleaseEvent( QgsMapMouseEvent * e ) { //check if we operate on a vector layer QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() ); if ( !vlayer ) { notifyNotVectorLayer(); return; } if ( !vlayer->isEditable() ) { notifyNotEditableLayer(); return; } //add point to list and to rubber band if ( e->button() == Qt::LeftButton ) { int error = addVertex( e->mapPoint() ); if ( error == 1 ) { //current layer is not a vector layer return; } else if ( error == 2 ) { //problem with coordinate transformation emit messageEmitted( tr( "Cannot transform the point to the layers coordinate system" ), QgsMessageBar::WARNING ); return; } startCapturing(); } else if ( e->button() == Qt::RightButton ) { if ( !isCapturing() ) return; deleteTempRubberBand(); closePolygon(); vlayer->beginEditCommand( tr( "Ring added and filled" ) ); QList< QgsPoint > pointList = points(); QgsFeatureId modifiedFid; int addRingReturnCode = vlayer->addRing( pointList, &modifiedFid ); if ( addRingReturnCode != 0 ) { QString errorMessage; //todo: open message box to communicate errors if ( addRingReturnCode == 1 ) { errorMessage = tr( "a problem with geometry type occured" ); } else if ( addRingReturnCode == 2 ) { errorMessage = tr( "the inserted Ring is not closed" ); } else if ( addRingReturnCode == 3 ) { errorMessage = tr( "the inserted Ring is not a valid geometry" ); } else if ( addRingReturnCode == 4 ) { errorMessage = tr( "the inserted Ring crosses existing rings" ); } else if ( addRingReturnCode == 5 ) { errorMessage = tr( "the inserted Ring is not contained in a feature" ); } else { errorMessage = tr( "an unknown error occured" ); } emit messageEmitted( tr( "could not add ring since %1." ).arg( errorMessage ), QgsMessageBar::CRITICAL ); vlayer->destroyEditCommand(); } else { // find parent feature and get it attributes double xMin, xMax, yMin, yMax; QgsRectangle bBox; xMin = std::numeric_limits<double>::max(); xMax = -std::numeric_limits<double>::max(); yMin = std::numeric_limits<double>::max(); yMax = -std::numeric_limits<double>::max(); Q_FOREACH ( const QgsPoint& point, pointList ) { xMin = qMin( xMin, point.x() ); xMax = qMax( xMax, point.x() ); yMin = qMin( yMin, point.y() ); yMax = qMax( yMax, point.y() ); } bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin ); bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax ); QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterFid( modifiedFid ) ); QgsFeature f; bool res = false; if ( fit.nextFeature( f ) ) { //create QgsFeature with wkb representation QgsFeature* ft = new QgsFeature( vlayer->fields(), 0 ); ft->setGeometry( QgsGeometry::fromPolygon( QgsPolygon() << pointList.toVector() ) ); ft->setAttributes( f.attributes() ); if ( QApplication::keyboardModifiers() == Qt::ControlModifier ) { res = vlayer->addFeature( *ft ); } else { QgsAttributeDialog *dialog = new QgsAttributeDialog( vlayer, ft, false, NULL, true ); dialog->setIsAddDialog( true ); res = dialog->exec(); // will also add the feature } if ( res ) { vlayer->endEditCommand(); } else { delete ft; vlayer->destroyEditCommand(); } res = false; } } stopCapturing(); }