2

So I am running QGIS 2.8.1 on Ubuntu 14.04. This following problem is happening in my script, but also occurs directly in the QGIS python console:

lay = iface.activeLayer()
lay.featureCount()
1L
lay.type()
0
prov = lay.dataProvider()
prov.geometryType()
3
geom = lay.getFeatures().next().geometry()
geom
<qgis._core.QgsGeometry object at 0x7fff4d5f90e8>

Next, if I do pretty much anything with that QgsGeometry object I get a dizzying array of Segmentation faults. I noticed it first when I was trying to intersection tests with other geometries, but even simple calls like geom.type() results in :

Program received signal SIGSEGV, Segmentation fault.
0x00007fffefe0c3ca in _int_free (av=0x0, p=0x5042970, have_lock=0)
at malloc.c:3943

but mostly it has to do with the GEOS related functions:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff123798f in GEOSGeom_destroy_r () from /usr/lib/libgeos_c.so.1

is this a known bug? http://hub.qgis.org/issues/777

2

I reproduced this in QGIS 2.14.2 on Ubuntu, both in Console and in a saved .py script.

The issue you linked to has the answer - change your call from .geometry() to .geometryAndOwnership(). I tried that and it fixes the problem.

According to the API docs this method is deprecated and you should use constGeometry() instead - but I find this also segfaults.

From the issue, it seems the feature object is 'lost' by the time it gets to your .type() call, and it's taken the geometry with it. You might also be able to get around this by assigning things one at a time, rather than by method chaining, but not tried this.

EDIT

I tried unrolling the method chaining - this works.

lay = iface.activeLayer()
print lay.featureCount()
print lay.type()
prov = lay.dataProvider()
print prov.geometryType()
features = lay.getFeatures()
nextfeature = features.next()
geom = nextfeature.geometry()
print geom
print geom.getType()
  • Thanks, this worked like a charm and, I suppose, it will be also work when the API moves to 3.0. (unlike constGeometry) – Kris May 4 '16 at 9:00
  • 1
    Actually it will also be removed for 3.0. there'll be a single . geometry() getter and .setGeometry(...) setter. Either way, you'll need to update code. – ndawson May 4 '16 at 20:56
4

It's a known issue, which will be fixed when QGIS moves to QGIS 3.0 development (since the fix could potentially break existing plugins).

To work around it, you need to force a copy of the geometry:

geom = QgsGeometry( lay.getFeatures().next().geometry() )

Technical explanation below:

Calling just

geom = lay.getFeatures().next().geometry()

results in a reference to a "temporary" geometry (a c++ object), which will go out of scope and be deleted together with its owner feature (ie, the QgsFeature returned by lay.getFeatures().next()). Since you're not keeping a reference to the feature itself around, it will get garbage collected almost immediately by python and its geometry will be deleted too. Making a copy of the geometry by using QgsGeometry(...) will result in a geometry which python has full ownership over and will be correctly kept around for the required lifetime of the python object.

Explanation of constGeometry()

Note that it's more efficient to use feature.constGeometry() in place of feature.geometry(). Behind the scenes (in the c++ code), calling feature.geometry() can sometimes force a full copy of the feature to be made, which is expensive. Calling instead feature.constGeometry() will never make this unnecessary copy.

(All this mess is scheduled to be cleaned up for QGIS 3.0!)

  • Thanks for the clarification. Can't wait for 3.0, when all our problems will be solved! ;) constGeometry was added in 2.9 and I'm running 2.8.1. Unchaining the method calls worked for me as @steven-kay suggested. – Kris May 4 '16 at 8:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.