[GIS] How to display local file’s geometries as rubber bands in QGIS

pyqgispythonqgis

I'd like to get geometries from a local file (e.g. GML) displayed as rubber bands (QgsRubberBands) in QGIS. However, I wouldn't like to load the layer into the map because in the real scenario there could be a large number of files to get geometries from.

I've been attempting it with the following code (you can copy it directly to the QGIS Python Console), but the problem is that only the last feature is displayed:

from qgis.core import QgsFeature, QgsVectorLayer
from qgis.gui import QgsRubberBand
def loadGMLAsRubberBands(fileName):
    featList = []   
    rb = QgsRubberBand(qgis.utils.iface.mapCanvas(), True)
    vlayer = QgsVectorLayer(fileName, "layer", "ogr")
    allAttrs = vlayer.dataProvider().attributeIndexes()
    vlayer.select(allAttrs)        
    f = QgsFeature()
    while vlayer.dataProvider().nextFeature(f):
        featList.append(f)          
        rb.addGeometry(featList[-1].geometry(), None)   

loadGMLAsRubberBands("/tmp/gml/sample_three_features.gml")

A sample GML file can be found here.

I've already attempted several things with no success, namely to store layers (vlayer), features, geometries and/or rubber bands in a list (as suggested in some QGIS mailing-list threads).

I'm using QGIS 1.8.0-Lisboa (rev. a1255fc), Python v.2.7.2, GDAL/OGR v.1.7.3 on Ubuntu/Linux.

Any help would be appreciated.

Best Answer

Since there is a bug with multi-polygons (thanks to @Nathan W), I added more code to the script and now it works. Basically, I adapted the code from the QGIS fTools plugin to convert multi-polygons into polygons as a workaround.

Now all features are displayed!

from qgis.core import QgsFeature, QgsVectorLayer
from qgis.gui import QgsRubberBand
def loadGMLAsRubberBands(fileName):
    featureList = []   
    rb = QgsRubberBand(qgis.utils.iface.mapCanvas(), True)
    vlayer = QgsVectorLayer(fileName, "layer", "ogr")
    vprovider = vlayer.dataProvider()
    allAttrs = vprovider.attributeIndexes()
    vlayer.select(allAttrs)       
    # Next code is adapted from fTools plugin 
    inFeat = QgsFeature()
    outFeat = QgsFeature()
    inGeom = QgsGeometry()
    while vprovider.nextFeature( inFeat ):
        inGeom = inFeat.geometry()
        featList = extractAsSingle( inGeom )
        for i in featList:
          outFeat.setGeometry( i )
          featureList.append( outFeat )
          rb.addGeometry(featureList[-1].geometry(), None)  

def extractAsSingle( geom ):
    # Code from QGIS fTools plugin
    multi_geom = QgsGeometry()
    temp_geom = []
    if geom.type() == 0:
      if geom.isMultipart():
        multi_geom = geom.asMultiPoint()
        for i in multi_geom:
          temp_geom.append( QgsGeometry().fromPoint ( i ) )
      else:
        temp_geom.append( geom )
    elif geom.type() == 1:
      if geom.isMultipart():
        multi_geom = geom.asMultiPolyline()
        for i in multi_geom:
          temp_geom.append( QgsGeometry().fromPolyline( i ) )
      else:
        temp_geom.append( geom )
    elif geom.type() == 2:
      if geom.isMultipart():
        multi_geom = geom.asMultiPolygon()
        for i in multi_geom:
          temp_geom.append( QgsGeometry().fromPolygon( i ) )
      else:
        temp_geom.append( geom )
    return temp_geom


loadGMLAsRubberBands("/tmp/gml/sample_three_features.gml")
Related Question