[QGIS-Developer] get all the features of a specific layer which are visible in the viewport

Jorge Gustavo Rocha jgr at di.uminho.pt
Sun Jan 19 07:36:27 PST 2020


Hi Jo,

You can use setFilterRect (see
https://docs.qgis.org/3.4/en/docs/pyqgis_developer_cookbook/vector.html).

request = QgsFeatureRequest().setFilterRect(iface.mapCanvas().extent())
for feature in layer.getFeatures(request):
	print(feature.id)

This way, you only iterate over the visible features.

Regards,

Jorge Gustavo

On 18/01/20 20:39, Jo wrote:
> Hi,
> 
> I created the following code:
> 
> class FBSegmentPoiComboBox(FBComboBox):
>     def __init__(self, name, identifier=None, update_method=None, iface=None):
>         super().__init__(name=name, identifier=identifier, update_method=update_method)
>         self.iface = iface
>         self.items_list = []
>         self.find_segments()
>         self.rubber_band = QgsRubberBand(self.iface.mapCanvas(), False)
>         self.rubber_band.setWidth(12)
>         self.rubber_band.setStrokeColor(QColor.fromRgb(90, 0, 20))
>         self.highlighted.connect(self.highlight_segment)
>         self.currentIndexChanged.connect(self.clear_rubberband)
> 
>     def find_segments(self):
>         self.clear()
>         self.add_item(REFRESH_SEGMENTS_LIST, None)
>         # put a dummy at position 0
> self.items_list = ['dummy']
>         segment_layer_list = QgsProject.instance().mapLayersByName('segment')
>         if segment_layer_list:
>             segment_layer = segment_layer_list[0]
>             layer = QgsProject.instance().layerTreeRoot().findLayer(segment_layer)
>             if layer:
>                 layer.setItemVisibilityChecked(True)
>             if self.iface:
>                 segments = QgsSpatialIndex()
>                 for segment in segment_layer.getFeatures():
>                     segments.insertFeature(segment)
>                 nearby = segments.nearestNeighbor(self.iface.mapCanvas().center(), neighbors=10) # , maxDistance=1000)
> for featureId in nearby:
>                     fit2 = segment_layer.getFeatures(QgsFeatureRequest().setFilterFid(featureId))
>                     ftr = QgsFeature()
>                     fit2.nextFeature(ftr)
>                     self.add_item(ftr.attribute(0), ftr.attribute(0))
>                     self.items_list.append(ftr)
>         self.changed = False
> 
> def highlight_segment(self, index):
>         self.rubber_band.reset()
>         if index == 0:
>             self.find_segments()
>         elif index < len(self.items_list):
>             self.rubber_band.setToGeometry(self.items_list[index].geometry())
> 
>     def clear_rubberband(self, index):
>         self.rubber_band.reset()
> 
> 
> It populates a drop down with all the LineStrings near to the center of the screen.
> 
> It's not very efficient though, as I need to first pass all the LineStrings on that particular layer to it.
> 
> Is there a way to replace this code:
> 
>                 for segment in segment_layer.getFeatures():
>                     segments.insertFeature(segment)
> 
> So it only works on a smaller subset of features that are actually visible to on the user's screen?
> 
> Jo
> 
> 
> _______________________________________________
> QGIS-Developer mailing list
> QGIS-Developer at lists.osgeo.org
> List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer
> Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer
> 

J. Gustavo
-- 
Jorge Gustavo Rocha
Departamento de Informática
Universidade do Minho
4710-057 Braga
Gabinete 3.29 (Piso 3)
Tel: +351 253604480
Fax: +351 253604471
Móvel: +351 910333888
skype: nabocudnosor


More information about the QGIS-Developer mailing list