bool QgsMemoryFeatureIterator::nextFeatureTraverseAll( QgsFeature& feature ) { bool hasFeature = false; // option 2: traversing the whole layer while ( mSelectIterator != mSource->mFeatures.constEnd() ) { if ( mRequest.filterRect().isNull() ) { // selection rect empty => using all features hasFeature = true; } else { if ( mRequest.flags() & QgsFeatureRequest::ExactIntersect ) { // using exact test when checking for intersection if ( mSelectIterator->hasGeometry() && mSelectIterator->geometry().intersects( mSelectRectGeom ) ) hasFeature = true; } else { // check just bounding box against rect when not using intersection if ( mSelectIterator->hasGeometry() && mSelectIterator->geometry().boundingBox().intersects( mRequest.filterRect() ) ) hasFeature = true; } } if ( mSubsetExpression ) { mSource->mExpressionContext.setFeature( *mSelectIterator ); if ( !mSubsetExpression->evaluate( &mSource->mExpressionContext ).toBool() ) hasFeature = false; } if ( hasFeature ) break; ++mSelectIterator; } // copy feature if ( hasFeature ) { feature = mSelectIterator.value(); ++mSelectIterator; feature.setValid( true ); feature.setFields( mSource->mFields ); // allow name-based attribute lookups } else close(); return hasFeature; }
bool QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature ) { feature.setFeatureId( OGR_F_GetFID( fet ) ); feature.initAttributes( P->fields().count() ); feature.setFields( &P->mAttributeFields ); // allow name-based attribute lookups bool fetchGeom = !( mRequest.flags() & QgsFeatureRequest::NoGeometry ); bool useIntersect = mRequest.flags() & QgsFeatureRequest::ExactIntersect; bool geometryTypeFilter = P->mOgrGeometryTypeFilter != wkbUnknown; if ( fetchGeom || useIntersect || geometryTypeFilter ) { OGRGeometryH geom = OGR_F_GetGeometryRef( fet ); if ( geom ) { // get the wkb representation unsigned char *wkb = new unsigned char[OGR_G_WkbSize( geom )]; OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb ); feature.setGeometryAndOwnership( wkb, OGR_G_WkbSize( geom ) ); } if (( useIntersect && ( !feature.geometry() || !feature.geometry()->intersects( mRequest.filterRect() ) ) ) || ( geometryTypeFilter && ( !feature.geometry() || wkbFlatten(( OGRwkbGeometryType )feature.geometry()->wkbType() ) != wkbFlatten( P->mOgrGeometryTypeFilter ) ) ) ) { OGR_F_Destroy( fet ); return false; } } if ( !fetchGeom ) { feature.setGeometry( 0 ); } // fetch attributes if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) { const QgsAttributeList& attrs = mRequest.subsetOfAttributes(); for ( QgsAttributeList::const_iterator it = attrs.begin(); it != attrs.end(); ++it ) { getFeatureAttribute( fet, feature, *it ); } } else { // all attributes for ( int idx = 0; idx < P->mAttributeFields.count(); ++idx ) { getFeatureAttribute( fet, feature, idx ); } } return true; }
bool QgsVectorLayerFeatureIterator::nextFeature( QgsFeature& f ) { f.setValid( false ); if ( mClosed ) return false; if ( mRequest.filterType() == QgsFeatureRequest::FilterFid ) { if ( mFetchedFid ) return false; bool res = nextFeatureFid( f ); mFetchedFid = true; return res; } if ( mRequest.filterType() == QgsFeatureRequest::FilterRect ) { if ( fetchNextChangedGeomFeature( f ) ) return true; // no more changed geometries } if ( fetchNextAddedFeature( f ) ) return true; // no more added features while ( mProviderIterator.nextFeature( f ) ) { if ( mFetchConsidered.contains( f.id() ) ) continue; // TODO[MD]: just one resize of attributes f.setFields( &L->mUpdatedFields ); // update attributes updateChangedAttributes( f ); if ( !mFetchJoinInfo.isEmpty() ) addJoinedAttributes( f ); // update geometry if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) updateFeatureGeometry( f ); return true; } close(); return false; }
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 ); }
bool QgsMemoryFeatureIterator::nextFeatureTraverseAll( QgsFeature& feature ) { bool hasFeature = false; // option 2: traversing the whole layer while ( mSelectIterator != P->mFeatures.end() ) { if ( mRequest.filterType() != QgsFeatureRequest::FilterRect ) { // selection rect empty => using all features hasFeature = true; } else { if ( mRequest.flags() & QgsFeatureRequest::ExactIntersect ) { // using exact test when checking for intersection if ( mSelectIterator->geometry()->intersects( mSelectRectGeom ) ) hasFeature = true; } else { // check just bounding box against rect when not using intersection if ( mSelectIterator->geometry()->boundingBox().intersects( mRequest.filterRect() ) ) hasFeature = true; } } if ( hasFeature ) break; mSelectIterator++; } // copy feature if ( hasFeature ) { feature = mSelectIterator.value(); mSelectIterator++; feature.setValid( true ); feature.setFields( &P->mFields ); // allow name-based attribute lookups } else close(); return hasFeature; }
bool QgsMemoryFeatureIterator::nextFeatureUsingList( QgsFeature &feature ) { bool hasFeature = false; // option 1: we have a list of features to traverse while ( mFeatureIdListIterator != mFeatureIdList.constEnd() ) { if ( !mFilterRect.isNull() && mRequest.flags() & QgsFeatureRequest::ExactIntersect ) { // do exact check in case we're doing intersection if ( mSource->mFeatures.value( *mFeatureIdListIterator ).hasGeometry() && mSelectRectEngine->intersects( mSource->mFeatures.value( *mFeatureIdListIterator ).geometry().constGet() ) ) hasFeature = true; } else hasFeature = true; if ( mSubsetExpression ) { mSource->mExpressionContext.setFeature( mSource->mFeatures.value( *mFeatureIdListIterator ) ); if ( !mSubsetExpression->evaluate( &mSource->mExpressionContext ).toBool() ) hasFeature = false; } if ( hasFeature ) break; ++mFeatureIdListIterator; } // copy feature if ( hasFeature ) { feature = mSource->mFeatures.value( *mFeatureIdListIterator ); ++mFeatureIdListIterator; } else close(); if ( hasFeature ) { feature.setFields( mSource->mFields ); // allow name-based attribute lookups geometryToDestinationCrs( feature, mTransform ); } return hasFeature; }
bool QgsMssqlFeatureIterator::fetchFeature( QgsFeature& feature ) { feature.setValid( false ); if ( !mQuery ) return false; if ( !mQuery->isActive() ) { QgsDebugMsg( "Read attempt on inactive query" ); return false; } if ( mQuery->next() ) { feature.initAttributes( mSource->mFields.count() ); feature.setFields( &mSource->mFields ); // allow name-based attribute lookups for ( int i = 0; i < mAttributesToFetch.count(); i++ ) { QVariant v = mQuery->value( i ); feature.setAttribute( mAttributesToFetch[i], mQuery->value( i ) ); } if ( mFidCol >= 0 ) { feature.setFeatureId( mQuery->value( mFidCol ).toLongLong() ); } if ( mGeometryCol >= 0 ) { QByteArray ar = mQuery->value( mGeometryCol ).toByteArray(); unsigned char* wkb = mParser.ParseSqlGeometry(( unsigned char* )ar.data(), ar.size() ); if ( wkb ) { feature.setGeometryAndOwnership( wkb, mParser.GetWkbLen() ); } } feature.setValid( true ); return true; } return false; }
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 QgsWFSFeatureIterator::copyFeature( const QgsFeature* f, QgsFeature& feature, bool fetchGeometry ) { Q_UNUSED( fetchGeometry ); if ( !f ) { return; } //copy the geometry const QgsGeometry* geometry = f->constGeometry(); if ( geometry && fetchGeometry ) { const unsigned char *geom = geometry->asWkb(); int geomSize = geometry->wkbSize(); unsigned char* copiedGeom = new unsigned char[geomSize]; memcpy( copiedGeom, geom, geomSize ); QgsGeometry *g = new QgsGeometry(); g->fromWkb( copiedGeom, geomSize ); feature.setGeometry( g ); } else { feature.setGeometry( nullptr ); } //and the attributes feature.initAttributes( mSource->mFields.size() ); for ( int i = 0; i < mSource->mFields.size(); i++ ) { const QVariant &v = f->attributes().value( i ); if ( v.type() != mSource->mFields.at( i ).type() ) feature.setAttribute( i, QgsVectorDataProvider::convertValue( mSource->mFields.at( i ).type(), v.toString() ) ); else feature.setAttribute( i, v ); } //id and valid feature.setValid( true ); feature.setFeatureId( f->id() ); feature.setFields( mSource->mFields ); // allow name-based attribute lookups }
void QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature ) { feature.setFeatureId( OGR_F_GetFID( fet ) ); feature.initAttributes( P->fields().count() ); feature.setFields( &P->mAttributeFields ); // allow name-based attribute lookups // fetch geometry if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) { OGRGeometryH geom = OGR_F_GetGeometryRef( fet ); if ( geom ) { // get the wkb representation unsigned char *wkb = new unsigned char[OGR_G_WkbSize( geom )]; OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb ); feature.setGeometryAndOwnership( wkb, OGR_G_WkbSize( geom ) ); } else { feature.setGeometry( 0 ); } } // fetch attributes if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) { const QgsAttributeList& attrs = mRequest.subsetOfAttributes(); for ( QgsAttributeList::const_iterator it = attrs.begin(); it != attrs.end(); ++it ) { getFeatureAttribute( fet, feature, *it ); } } else { // all attributes for ( int idx = 0; idx < P->mAttributeFields.count(); ++idx ) { getFeatureAttribute( fet, feature, idx ); } } }
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 ); }
bool QgsOgrUtils::readOgrFeatureAttributes( OGRFeatureH ogrFet, const QgsFields& fields, QgsFeature& feature, QTextCodec* encoding ) { // read all attributes feature.initAttributes( fields.count() ); feature.setFields( fields ); if ( !ogrFet ) return false; bool ok = false; for ( int idx = 0; idx < fields.count(); ++idx ) { QVariant value = getOgrFeatureAttribute( ogrFet, fields, idx, encoding, &ok ); if ( ok ) { feature.setAttribute( idx, value ); } } return true; }
bool QgsGPXFeatureIterator::readRoute( const QgsRoute &rte, QgsFeature &feature ) { if ( rte.points.isEmpty() ) return false; QgsGeometry *geometry = readRouteGeometry( rte ); if ( !mFilterRect.isNull() ) { if ( ( rte.xMax < mFilterRect.xMinimum() ) || ( rte.xMin > mFilterRect.xMaximum() ) || ( rte.yMax < mFilterRect.yMinimum() ) || ( rte.yMin > mFilterRect.yMaximum() ) ) { delete geometry; return false; } if ( !geometry->intersects( mFilterRect ) ) //use geos for precise intersection test { delete geometry; return false; } } if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) { feature.setGeometry( *geometry ); delete geometry; } else { delete geometry; } feature.setId( rte.id ); feature.setValid( true ); feature.setFields( mSource->mFields ); // allow name-based attribute lookups feature.initAttributes( mSource->mFields.count() ); readAttributes( feature, rte ); return true; }
bool QgsGPXFeatureIterator::readTrack( const QgsTrack &trk, QgsFeature &feature ) { //QgsDebugMsg( QString( "GPX feature track segments: %1" ).arg( trk.segments.size() ) ); QgsGeometry *geometry = readTrackGeometry( trk ); if ( !mFilterRect.isNull() ) { if ( ( trk.xMax < mFilterRect.xMinimum() ) || ( trk.xMin > mFilterRect.xMaximum() ) || ( trk.yMax < mFilterRect.yMinimum() ) || ( trk.yMin > mFilterRect.yMaximum() ) ) { delete geometry; return false; } if ( !geometry->intersects( mFilterRect ) ) //use geos for precise intersection test { delete geometry; return false; } } if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) { feature.setGeometry( *geometry ); delete geometry; } else { delete geometry; } feature.setId( trk.id ); feature.setValid( true ); feature.setFields( mSource->mFields ); // allow name-based attribute lookups feature.initAttributes( mSource->mFields.count() ); readAttributes( feature, trk ); return true; }
bool QgsMemoryFeatureIterator::nextFeatureUsingList( QgsFeature& feature ) { bool hasFeature = false; // option 1: we have a list of features to traverse while ( mFeatureIdListIterator != mFeatureIdList.constEnd() ) { if ( mRequest.filterType() == QgsFeatureRequest::FilterRect && mRequest.flags() & QgsFeatureRequest::ExactIntersect ) { // do exact check in case we're doing intersection if ( mSource->mFeatures[*mFeatureIdListIterator].geometry() && mSource->mFeatures[*mFeatureIdListIterator].geometry()->intersects( mSelectRectGeom ) ) hasFeature = true; } else hasFeature = true; if ( mSubsetExpression && !mSubsetExpression->evaluate( mSource->mFeatures[*mFeatureIdListIterator] ).toBool() ) hasFeature = false; if ( hasFeature ) break; ++mFeatureIdListIterator; } // copy feature if ( hasFeature ) { feature = mSource->mFeatures[*mFeatureIdListIterator]; ++mFeatureIdListIterator; } else close(); if ( hasFeature ) feature.setFields( &mSource->mFields ); // allow name-based attribute lookups return hasFeature; }
bool QgsGPXFeatureIterator::readRoute( const QgsRoute& rte, QgsFeature& feature ) { if ( rte.points.size() == 0 ) return false; QgsGeometry* theGeometry = readRouteGeometry( rte ); if ( mRequest.filterType() == QgsFeatureRequest::FilterRect ) { const QgsRectangle& rect = mRequest.filterRect(); if (( rte.xMax < rect.xMinimum() ) || ( rte.xMin > rect.xMaximum() ) || ( rte.yMax < rect.yMinimum() ) || ( rte.yMin > rect.yMaximum() ) ) return false; if ( !theGeometry->intersects( rect ) ) //use geos for precise intersection test { delete theGeometry; return false; } } if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) { feature.setGeometry( theGeometry ); } else { delete theGeometry; } feature.setFeatureId( rte.id ); feature.setValid( true ); feature.setFields( &mSource->mFields ); // allow name-based attribute lookups feature.initAttributes( mSource->mFields.count() ); readAttributes( feature, rte ); return true; }
bool QgsGPXFeatureIterator::readWaypoint( const QgsWaypoint& wpt, QgsFeature& feature ) { if ( mRequest.filterType() == QgsFeatureRequest::FilterRect ) { const QgsRectangle& rect = mRequest.filterRect(); if ( ! rect.contains( QgsPoint( wpt.lon, wpt.lat ) ) ) return false; } // some wkb voodoo if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) { feature.setGeometry( readWaypointGeometry( wpt ) ); } feature.setFeatureId( wpt.id ); feature.setValid( true ); feature.setFields( &mSource->mFields ); // allow name-based attribute lookups feature.initAttributes( mSource->mFields.count() ); readAttributes( feature, wpt ); return true; }
bool QgsGPXFeatureIterator::readWaypoint( const QgsWaypoint &wpt, QgsFeature &feature ) { if ( !mFilterRect.isNull() ) { if ( ! mFilterRect.contains( QgsPointXY( wpt.lon, wpt.lat ) ) ) return false; } // some wkb voodoo if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) { QgsGeometry *g = readWaypointGeometry( wpt ); feature.setGeometry( *g ); delete g; } feature.setId( wpt.id ); feature.setValid( true ); feature.setFields( mSource->mFields ); // allow name-based attribute lookups feature.initAttributes( mSource->mFields.count() ); readAttributes( feature, wpt ); return true; }
bool QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature ) { feature.setFeatureId( OGR_F_GetFID( fet ) ); feature.initAttributes( mSource->mFields.count() ); feature.setFields( &mSource->mFields ); // allow name-based attribute lookups bool useIntersect = mRequest.flags() & QgsFeatureRequest::ExactIntersect; bool geometryTypeFilter = mSource->mOgrGeometryTypeFilter != wkbUnknown; if ( mFetchGeometry || useIntersect || geometryTypeFilter ) { OGRGeometryH geom = OGR_F_GetGeometryRef( fet ); if ( geom ) { if ( mGeometrySimplifier ) mGeometrySimplifier->simplifyGeometry( geom ); // get the wkb representation int memorySize = OGR_G_WkbSize( geom ); unsigned char *wkb = new unsigned char[memorySize]; OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb ); QgsGeometry* geometry = feature.geometry(); if ( !geometry ) feature.setGeometryAndOwnership( wkb, memorySize ); else geometry->fromWkb( wkb, memorySize ); } else feature.setGeometry( 0 ); if (( useIntersect && ( !feature.geometry() || !feature.geometry()->intersects( mRequest.filterRect() ) ) ) || ( geometryTypeFilter && ( !feature.geometry() || QgsOgrProvider::ogrWkbSingleFlatten(( OGRwkbGeometryType )feature.geometry()->wkbType() ) != mSource->mOgrGeometryTypeFilter ) ) ) { OGR_F_Destroy( fet ); return false; } } if ( !mFetchGeometry ) { feature.setGeometry( 0 ); } // fetch attributes if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) { const QgsAttributeList& attrs = mRequest.subsetOfAttributes(); for ( QgsAttributeList::const_iterator it = attrs.begin(); it != attrs.end(); ++it ) { getFeatureAttribute( fet, feature, *it ); } } else { // all attributes for ( int idx = 0; idx < mSource->mFields.count(); ++idx ) { getFeatureAttribute( fet, feature, idx ); } } return true; }
bool QgsVectorLayerFeatureIterator::fetchFeature( QgsFeature& f ) { f.setValid( false ); if ( mClosed ) return false; if ( mRequest.filterType() == QgsFeatureRequest::FilterFid ) { if ( mFetchedFid ) return false; bool res = nextFeatureFid( f ); mFetchedFid = true; return res; } if ( mRequest.filterType() == QgsFeatureRequest::FilterRect ) { if ( fetchNextChangedGeomFeature( f ) ) return true; // no more changed geometries } if ( mRequest.filterType() == QgsFeatureRequest::FilterExpression ) { if ( fetchNextChangedAttributeFeature( f ) ) return true; // no more changed features } while ( fetchNextAddedFeature( f ) ) { return true; } // no more added features if ( mProviderIterator.isClosed() ) { mChangedFeaturesIterator.close(); mProviderIterator = mSource->mProviderFeatureSource->getFeatures( mProviderRequest ); } while ( mProviderIterator.nextFeature( f ) ) { if ( mFetchConsidered.contains( f.id() ) ) continue; // TODO[MD]: just one resize of attributes f.setFields( &mSource->mFields ); // update attributes updateChangedAttributes( f ); addVirtualAttributes( f ); // update geometry // TODO[MK]: FilterRect check after updating the geometry if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) updateFeatureGeometry( f ); return true; } // no more provider features close(); return false; }
bool QgsVirtualLayerFeatureIterator::fetchFeature( QgsFeature &feature ) { feature.setValid( false ); if ( mClosed ) { return false; } bool skipFeature = false; do { if ( mQuery->step() != SQLITE_ROW ) { return false; } feature.setFields( mSource->mFields, /* init */ true ); if ( mSource->mDefinition.uid().isNull() && mRequest.filterType() != QgsFeatureRequest::FilterFid ) { // no id column => autoincrement feature.setId( mFid++ ); } else { // first column: uid feature.setId( mQuery->columnInt64( 0 ) ); } int n = mQuery->columnCount(); int i = 0; const auto constMAttributes = mAttributes; for ( int idx : constMAttributes ) { int type = mQuery->columnType( i + 1 ); switch ( type ) { case SQLITE_INTEGER: feature.setAttribute( idx, mQuery->columnInt64( i + 1 ) ); break; case SQLITE_FLOAT: feature.setAttribute( idx, mQuery->columnDouble( i + 1 ) ); break; case SQLITE_TEXT: default: feature.setAttribute( idx, mQuery->columnText( i + 1 ) ); break; }; i++; } if ( n > mAttributes.size() + 1 ) { // geometry field QByteArray blob( mQuery->columnBlob( n - 1 ) ); if ( blob.size() > 0 ) { feature.setGeometry( spatialiteBlobToQgsGeometry( blob.constData(), blob.size() ) ); } else { feature.clearGeometry(); } } feature.setValid( true ); geometryToDestinationCrs( feature, mTransform ); // if the FilterRect has not been applied on the query // apply it here by skipping features until they intersect if ( mSource->mDefinition.uid().isNull() && feature.hasGeometry() && mSource->mDefinition.hasDefinedGeometry() && !mFilterRect.isNull() ) { if ( mRequest.flags() & QgsFeatureRequest::ExactIntersect ) { // using exact test when checking for intersection skipFeature = !mRectEngine->intersects( feature.geometry().constGet() ); } else { // check just bounding box against rect when not using intersection skipFeature = !feature.geometry().boundingBox().intersects( mFilterRect ); } } } while ( skipFeature ); return true; }
bool QgsAfsProvider::getFeature( const QgsFeatureId &id, QgsFeature &f, bool fetchGeometry, const QList<int>& /*fetchAttributes*/, const QgsRectangle filterRect ) { // If cached, return cached feature QMap<QgsFeatureId, QgsFeature>::const_iterator it = mCache.find( id ); if ( it != mCache.end() ) { f = it.value(); return filterRect.isNull() || f.geometry().intersects( filterRect ); } // Determine attributes to fetch /*QStringList fetchAttribNames; foreach ( int idx, fetchAttributes ) fetchAttribNames.append( mFields.at( idx ).name() ); */ // When fetching from server, fetch all attributes and geometry by default so that we can cache them QStringList fetchAttribNames; QList<int> fetchAttribIdx; for ( int idx = 0, n = mFields.size(); idx < n; ++idx ) { fetchAttribNames.append( mFields.at( idx ).name() ); fetchAttribIdx.append( idx ); } fetchGeometry = true; // Fetch 100 features at the time int startId = ( id / 100 ) * 100; int stopId = qMin( startId + 100, mObjectIds.length() ); QList<quint32> objectIds; for ( int i = startId; i < stopId; ++i ) { objectIds.append( mObjectIds[i] ); } // Query QString errorTitle, errorMessage; QVariantMap queryData = QgsArcGisRestUtils::getObjects( mDataSource.param( "url" ), objectIds, mDataSource.param( "crs" ), fetchGeometry, fetchAttribNames, QgsWkbTypes::hasM( mGeometryType ), QgsWkbTypes::hasZ( mGeometryType ), filterRect, errorTitle, errorMessage ); if ( queryData.isEmpty() ) { const_cast<QgsAfsProvider*>( this )->pushError( errorTitle + ": " + errorMessage ); QgsDebugMsg( "Query returned empty result" ); return false; } QVariantList featuresData = queryData["features"].toList(); if ( featuresData.isEmpty() ) { QgsDebugMsg( "Query returned no features" ); return false; } for ( int i = 0, n = featuresData.size(); i < n; ++i ) { QVariantMap featureData = featuresData[i].toMap(); QgsFeature feature; // Set FID feature.setFeatureId( startId + i ); // Set attributes if ( !fetchAttribIdx.isEmpty() ) { QVariantMap attributesData = featureData["attributes"].toMap(); feature.setFields( mFields ); QgsAttributes attributes( mFields.size() ); foreach ( int idx, fetchAttribIdx ) { attributes[idx] = attributesData[mFields.at( idx ).name()]; } feature.setAttributes( attributes ); } // Set geometry if ( fetchGeometry ) { QVariantMap geometryData = featureData["geometry"].toMap(); QgsAbstractGeometry* geometry = QgsArcGisRestUtils::parseEsriGeoJSON( geometryData, queryData["geometryType"].toString(), QgsWkbTypes::hasM( mGeometryType ), QgsWkbTypes::hasZ( mGeometryType ) ); // Above might return 0, which is ok since in theory empty geometries are allowed feature.setGeometry( QgsGeometry( geometry ) ); } feature.setValid( true ); mCache.insert( feature.id(), feature ); }
bool QgsPostgresFeatureIterator::fetchFeature( QgsFeature& feature ) { feature.setValid( false ); if ( mClosed ) return false; if ( mFeatureQueue.empty() && !mLastFetch ) { QString fetch = QString( "FETCH FORWARD %1 FROM %2" ).arg( mFeatureQueueSize ).arg( mCursorName ); QgsDebugMsgLevel( QString( "fetching %1 features." ).arg( mFeatureQueueSize ), 4 ); if ( mConn->PQsendQuery( fetch ) == 0 ) // fetch features asynchronously { QgsMessageLog::logMessage( QObject::tr( "Fetching from cursor %1 failed\nDatabase error: %2" ).arg( mCursorName, mConn->PQerrorMessage() ), QObject::tr( "PostGIS" ) ); } QgsPostgresResult queryResult; for ( ;; ) { queryResult = mConn->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, mConn->PQerrorMessage() ), QObject::tr( "PostGIS" ) ); break; } int rows = queryResult.PQntuples(); if ( rows == 0 ) continue; mLastFetch = rows < mFeatureQueueSize; 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(); mSource->mShared->ensureFeaturesCountedAtLeast( mFetched ); return false; } feature = mFeatureQueue.dequeue(); mFetched++; feature.setValid( true ); feature.setFields( mSource->mFields ); // allow name-based attribute lookups 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; }
bool QgsSqlAnywhereFeatureIterator::nextFeature( QgsFeature& feature, SqlAnyStatement *stmt ) { feature.setValid( false ); bool fetchGeometry = !( mRequest.flags() & QgsFeatureRequest::NoGeometry ); bool subsetAttributes = mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes; if ( mClosed ) return false; if ( !P->mConnRO || !P->mConnRO->isAlive() ) { SaDebugMsg( "No database connection." ); return false; } bool ok; int id; a_sqlany_data_value geom; unsigned char *geomBuf = NULL; ok = ( stmt != NULL && stmt->fetchNext() ); // if no more rows... if ( !ok ) return false; if ( !fetchGeometry ) feature.setGeometryAndOwnership( 0, 0 ); int numAttributes = P->fields().count(); // also used later for sanity check feature.initAttributes( numAttributes ); feature.setFields( &P->mAttributeFields ); // allow name-based attribute lookups int i = 0; int numcols = stmt->numCols(); int colidx = 0; // Refers to which column we're on in "feature" (the row) for ( i = 0; i < numcols; i++ ) { if ( i == 0 ) { // first column always contains primary key ok = stmt->getInt( i, id ); if ( !ok ) break; QgsDebugMsgLevel( QString( "pid=%1" ).arg( id ), 3 ); feature.setFeatureId( id ); } else if ( i == 1 && fetchGeometry ) { // second column contains QKB geometry value ok = stmt->getColumn( i, &geom ); if ( !ok ) break; QgsDebugMsgLevel( QString( "retrieved geometry column" ), 3 ); geomBuf = new unsigned char[ *geom.length + 1 ]; memset( geomBuf, '\0', *geom.length ); memcpy( geomBuf, geom.buffer, *geom.length ); feature.setGeometryAndOwnership( geomBuf, *geom.length + 1 ); } else { if ( i == 1 ) { feature.setGeometryAndOwnership( 0, 0 ); // no geometry to fetch } int attrIndex = subsetAttributes ? mRequest.subsetOfAttributes()[colidx++] : colidx++; QVariant val; ok = stmt->getQVariant( i, val ); // ok may be false if value was NULL, but this is a valid return // Sanity check before setting the attribute value if ( colidx - 1 == i // First column is always pk, so colidx should be at least 1 behind || ( colidx - 1 == i - 1 && fetchGeometry ) // if fetchGeometry is true, colidx should be 2 behind || attrIndex >= numAttributes ) // index should always be less than the count { SaDebugMsg( QString( "Error retrieving feature column %1 with attribute index %2" ).arg( i ).arg( attrIndex ) ); return false; } // So now this should not crash. feature.setAttribute( attrIndex, val ); } } feature.setValid( true ); return true; }
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; }
QVariantMap QgsShortestPathPointToLayerAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { loadCommonParams( parameters, context, feedback ); QgsPointXY startPoint = parameterAsPoint( parameters, QStringLiteral( "START_POINT" ), context, mNetwork->sourceCrs() ); std::unique_ptr< QgsFeatureSource > endPoints( parameterAsSource( parameters, QStringLiteral( "END_POINTS" ), context ) ); if ( !endPoints ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "END_POINTS" ) ) ); QgsFields fields = endPoints->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" ) ) ); QVector< QgsPointXY > points; points.push_front( startPoint ); QHash< int, QgsAttributes > sourceAttributes; loadPoints( endPoints.get(), points, sourceAttributes, context, feedback ); feedback->pushInfo( QObject::tr( "Building graph…" ) ); QVector< QgsPointXY > snappedPoints; mDirector->makeGraph( mBuilder.get(), points, snappedPoints, feedback ); feedback->pushInfo( QObject::tr( "Calculating shortest paths…" ) ); QgsGraph *graph = mBuilder->graph(); int idxStart = graph->findVertex( snappedPoints[0] ); int idxEnd; QVector< int > tree; QVector< double > costs; QgsGraphAnalyzer::dijkstra( graph, idxStart, 0, &tree, &costs ); QVector<QgsPointXY> route; double cost; QgsFeature feat; feat.setFields( fields ); QgsAttributes attributes; int step = points.size() > 0 ? 100.0 / points.size() : 1; for ( int i = 1; i < points.size(); i++ ) { if ( feedback->isCanceled() ) { break; } idxEnd = graph->findVertex( snappedPoints[i] ); if ( tree.at( idxEnd ) == -1 ) { feedback->reportError( QObject::tr( "There is no route from start point (%1) to end point (%2)." ) .arg( startPoint.toString(), points[i].toString() ) ); feat.clearGeometry(); attributes = sourceAttributes.value( i ); attributes.append( QVariant() ); attributes.append( points[i].toString() ); feat.setAttributes( attributes ); sink->addFeature( feat, QgsFeatureSink::FastInsert ); continue; } route.clear(); route.push_front( graph->vertex( idxEnd ).point() ); cost = costs.at( idxEnd ); while ( idxEnd != idxStart ) { idxEnd = graph->edge( tree.at( idxEnd ) ).fromVertex(); route.push_front( graph->vertex( idxEnd ).point() ); } QgsGeometry geom = QgsGeometry::fromPolylineXY( route ); QgsFeature feat; feat.setFields( fields ); attributes = sourceAttributes.value( i ); attributes.append( startPoint.toString() ); attributes.append( points[i].toString() ); attributes.append( cost / mMultiplier ); feat.setAttributes( attributes ); feat.setGeometry( geom ); sink->addFeature( feat, QgsFeatureSink::FastInsert ); feedback->setProgress( i * step ); } QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), dest ); return outputs; }
bool QgsDelimitedTextFeatureIterator::nextFeatureInternal( QgsFeature& feature ) { QStringList tokens; QgsDelimitedTextFile *file = mSource->mFile; // If the iterator is not scanning the file, then it will have requested a specific // record, so only need to load that one. bool first = true; bool scanning = mMode == FileScan; while ( scanning || first ) { first = false; // before we do anything else, assume that there's something wrong with // the feature. If the provider is not currently valid, then cannot return // feature. feature.setValid( false ); QgsDelimitedTextFile::Status status = file->nextRecord( tokens ); if ( status == QgsDelimitedTextFile::RecordEOF ) break; if ( status != QgsDelimitedTextFile::RecordOk ) continue; // We ignore empty records, such as added randomly by spreadsheets if ( QgsDelimitedTextProvider::recordIsEmpty( tokens ) ) continue; QgsFeatureId fid = file->recordId(); while ( tokens.size() < mSource->mFieldCount ) tokens.append( QString::null ); QgsGeometry *geom = 0; // Load the geometry if required if ( mLoadGeometry ) { if ( mSource->mGeomRep == QgsDelimitedTextProvider::GeomAsWkt ) { geom = loadGeometryWkt( tokens ); } else if ( mSource->mGeomRep == QgsDelimitedTextProvider::GeomAsXy ) { geom = loadGeometryXY( tokens ); } if ( ! geom ) { continue; } } // At this point the current feature values are valid feature.setValid( true ); feature.setFields( &mSource->mFields ); // allow name-based attribute lookups feature.setFeatureId( fid ); feature.initAttributes( mSource->mFields.count() ); if ( geom ) feature.setGeometry( geom ); // If we are testing subset expression, then need all attributes just in case. // Could be more sophisticated, but probably not worth it! if ( ! mTestSubset && ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) ) { const QgsAttributeList& attrs = mRequest.subsetOfAttributes(); for ( QgsAttributeList::const_iterator i = attrs.begin(); i != attrs.end(); ++i ) { int fieldIdx = *i; fetchAttribute( feature, fieldIdx, tokens ); } } else { for ( int idx = 0; idx < mSource->mFields.count(); ++idx ) fetchAttribute( feature, idx, tokens ); } // If the iterator hasn't already filtered out the subset, then do it now if ( mTestSubset ) { QVariant isOk = mSource->mSubsetExpression->evaluate( &feature ); if ( mSource->mSubsetExpression->hasEvalError() ) continue; if ( ! isOk.toBool() ) continue; } // We have a good record, so return return true; } return false; }
bool QgsSpatiaLiteFeatureIterator::getFeature( sqlite3_stmt *stmt, QgsFeature &feature ) { bool subsetAttributes = mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes; int ret = sqlite3_step( stmt ); if ( ret == SQLITE_DONE ) { // there are no more rows to fetch return false; } if ( ret != SQLITE_ROW ) { // some unexpected error occurred QgsMessageLog::logMessage( QObject::tr( "SQLite error getting feature: %1" ).arg( QString::fromUtf8( sqlite3_errmsg( mHandle->handle() ) ) ), QObject::tr( "SpatiaLite" ) ); return false; } // one valid row has been fetched from the result set if ( !mFetchGeometry ) { // no geometry was required feature.setGeometryAndOwnership( 0, 0 ); } feature.initAttributes( mSource->mFields.count() ); feature.setFields( mSource->mFields ); // allow name-based attribute lookups int ic; int n_columns = sqlite3_column_count( stmt ); for ( ic = 0; ic < n_columns; ic++ ) { if ( ic == 0 ) { if ( mHasPrimaryKey ) { // first column always contains the ROWID (or the primary key) QgsFeatureId fid = sqlite3_column_int64( stmt, ic ); QgsDebugMsgLevel( QString( "fid=%1" ).arg( fid ), 3 ); feature.setFeatureId( fid ); } else { // autoincrement a row number mRowNumber++; feature.setFeatureId( mRowNumber ); } } else if ( mFetchGeometry && ic == mGeomColIdx ) { getFeatureGeometry( stmt, ic, feature ); } else { if ( subsetAttributes ) { if ( ic <= mRequest.subsetOfAttributes().size() ) { int attrIndex = mRequest.subsetOfAttributes()[ic-1]; feature.setAttribute( attrIndex, getFeatureAttribute( stmt, ic, mSource->mFields.at( attrIndex ).type() ) ); } } else { int attrIndex = ic - 1; feature.setAttribute( attrIndex, getFeatureAttribute( stmt, ic, mSource->mFields.at( attrIndex ).type() ) ); } } } return true; }
bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature ) { if ( mClosed ) return false; feature.setValid( false ); int cat = -1, type = -1, id = -1; QgsFeatureId featureId = -1; QgsDebugMsgLevel( "entered.", 3 ); /* TODO: handle editing if ( P->isEdited() || P->isFrozen() || !P->mValid ) { close(); return false; } */ // TODO: is this necessary? the same is checked below if ( !QgsGrassProvider::isTopoType( mSource->mLayerType ) && ( mSource->mCidxFieldIndex < 0 || mNextCidx >= mSource->mCidxFieldNumCats ) ) { close(); return false; // No features, no features in this layer } bool filterById = mRequest.filterType() == QgsFeatureRequest::FilterFid; // Get next line/area id int found = 0; while ( true ) { QgsDebugMsgLevel( QString( "mNextTopoId = %1" ).arg( mNextTopoId ), 3 ); if ( mSource->mLayerType == QgsGrassProvider::TOPO_POINT || mSource->mLayerType == QgsGrassProvider::TOPO_LINE ) { if ( mNextTopoId > Vect_get_num_lines( mSource->mMap ) ) break; id = mNextTopoId; type = Vect_read_line( mSource->mMap, 0, 0, mNextTopoId++ ); if ( !( type & mSource->mGrassType ) ) continue; featureId = id; } else if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) { if ( mNextTopoId > Vect_get_num_nodes( mSource->mMap ) ) break; id = mNextTopoId; type = 0; mNextTopoId++; featureId = id; } else { if ( mNextCidx >= mSource->mCidxFieldNumCats ) break; Vect_cidx_get_cat_by_index( mSource->mMap, mSource->mCidxFieldIndex, mNextCidx++, &cat, &type, &id ); // Warning: selection array is only of type line/area of current layer -> check type first if ( !( type & mSource->mGrassType ) ) continue; // The 'id' is a unique id of a GRASS geometry object (point, line, area) // but it cannot be used as QgsFeatureId because one geometry object may // represent more features because it may have more categories. featureId = makeFeatureId( id, cat ); } if ( filterById && featureId != mRequest.filterFid() ) continue; // it is correct to use id with mSelection because mSelection is only used // for geometry selection if ( !mSelection[id] ) continue; found = 1; break; } if ( !found ) { close(); return false; // No more features } QgsDebugMsgLevel( QString( "cat = %1 type = %2 id = %3 fatureId = %4" ).arg( cat ).arg( type ).arg( id ).arg( featureId ), 3 ); feature.setFeatureId( featureId ); feature.initAttributes( mSource->mFields.count() ); feature.setFields( &mSource->mFields ); // allow name-based attribute lookups if ( mRequest.flags() & QgsFeatureRequest::NoGeometry ) feature.setGeometry( 0 ); else setFeatureGeometry( feature, id, type ); if ( ! QgsGrassProvider::isTopoType( mSource->mLayerType ) ) { if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) setFeatureAttributes( cat, &feature, mRequest.subsetOfAttributes() ); else setFeatureAttributes( cat, &feature ); } else { feature.setAttribute( 0, id ); #if GRASS_VERSION_MAJOR < 7 if ( mSource->mLayerType == QgsGrassProvider::TOPO_POINT || mSource->mLayerType == QgsGrassProvider::TOPO_LINE ) #else /* No more topo points in GRASS 7 */ if ( mSource->mLayerType == QgsGrassProvider::TOPO_LINE ) #endif { feature.setAttribute( 1, QgsGrassProvider::primitiveTypeName( type ) ); int node1, node2; Vect_get_line_nodes( mSource->mMap, id, &node1, &node2 ); feature.setAttribute( 2, node1 ); if ( mSource->mLayerType == QgsGrassProvider::TOPO_LINE ) { feature.setAttribute( 3, node2 ); } } if ( mSource->mLayerType == QgsGrassProvider::TOPO_LINE ) { if ( type == GV_BOUNDARY ) { int left, right; Vect_get_line_areas( mSource->mMap, id, &left, &right ); feature.setAttribute( 4, left ); feature.setAttribute( 5, right ); } } else if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) { QString lines; int nlines = Vect_get_node_n_lines( mSource->mMap, id ); for ( int i = 0; i < nlines; i++ ) { int line = Vect_get_node_line( mSource->mMap, id, i ); if ( i > 0 ) lines += ","; lines += QString::number( line ); } feature.setAttribute( 1, lines ); } } feature.setValid( true ); return true; }