Category Archives: Sem categoria

Working properly with pyqgqis edit buffer to enable undo commands

Today I wanna share a solution for a problem we faced during the implementation of a tool for our QGIS plugin, DsgTools. The tool in question captures the signal featureAdded to get access to the newly created features for a particular QgsVectorLayer and change their attributes.

But, during our code testing we found a major problem. During the edition, when the undo button was pressed QGIS crashed big time!

So, how can you solve this problem? Surfing the web, lcoandrade and I have come across this: http://gis.stackexchange.com/questions/183423/qgis-crashes-when-doing-a-rollback-after-modifying-values-of-an-user-added-featu

By studing the link above and some other related, we have discovered that our function connected to featureAdded was messing things up, but why? Sure, we have learned some “kludges” or like some might say “McGyver Programming Stunts” to solve the problem, but what is the magic that happens when a user finishes adding a feature in QGIS? We need to understand that in order to code in an elegant way!

First of all, featureAdded() is triggered:


self.iface.actionAddFeature().trigger()

This triggers QgsMapToolAddFeature::addFeature which does the following


QgsFeatureAction *action = new QgsFeatureAction( tr( "add feature" ), *f, vlayer, QString(), -1, this );
bool res = action->addFeature( QgsAttributeMap(), showModal );

Which calls QgsFeatureAction::addFeature


mLayer->beginEditCommand( text() );
mFeatureSaved = mLayer->addFeature( *mFeature );

if ( mFeatureSaved )
mLayer->endEditCommand();
else
mLayer->destroyEditCommand();

So, between:


mLayer->beginEditCommand( text() );

and:


if ( mFeatureSaved )
mLayer->endEditCommand();
else
mLayer->destroyEditCommand();

QgsVectorLayer::addFeature is called


mFeatureSaved = mLayer->addFeature( *mFeature );

Which calls QgsVectorLayerEditBuffer::addFeature. It is only inside this method that the undo stack is updated.


L->undoStack()->push( new QgsVectorLayerUndoCommandAddFeature( this, f ) );

But, until endEditCommand() is called it is not possible to perform undo operations (http://pyqt.sourceforge.net/Docs/PyQt4/qundostack.html#beginMacro). Ok?

So let’s go back to our former coding, keeping in mind that if you decide to perform an Undo operation QGIS will Crash big time (http://qgis-developer.osgeo.narkive.com/5wnziigA/wrapping-changeattributevalue-between-begin-and-end-editcommand#post2).

Ok, on one hand I want to manipulate feature’s attributes when they are added, but on the other hand, if I try to do so, I’ll mess up the undo stack. How should we proceed? What if I only peep while QGIS does its magic and then I barge in and do my own stuff? So I have to have one slot connected to featureAdded signal just to let me know which features should I visit on the editBuffer and another slot connected to editCommandEnded signal, so that I am sure that the undoStack is properly built allowing me to revisit the added features to change its attributes.

Something like this:

myLayer.featureAdded.connect(self.storeFeaturesIds)
mylayer.editCommandEnded.connect(self.updateAttributesAfterAdding)

@pyqtSlot(int)
def storeFeaturesIds(self, featId):
     """
     This method only stores featIds in a class variable
     """
     self.addedFeatures.append(featId)

def updateAttributesAfterAdding(self):
     layer = self.sender() #here I can get the layer that has sent the signal
     while self.addedFeatures:
          featureId = self.addedFeatures.pop()
          #begining the edit command
          layer.beginEditCommand('Your command message here'))
          #Do your stuff here
     layer.endEditCommand()

So there it is, how to access attributes on the fly and not explode your QGIS while doing it!

Performing a HSV pan-sharpening in QGIS

Hi there guys!

Today I wanna talk about image pan-sharpening in QGIS.

I don’t want to enter in deeper technical details regarding pan-sharpening algorithms or something like that. I just want to focus on visual perception and image quality, ok?

QGIS in its processing toolbox has the ability to use the Orfeo toolbox (https://www.orfeo-toolbox.org). Orfeo is a great open-source software to perform image analysis. It is really great, believe me! But when talking about pan-sharpening it lacks the ability of perform HSV fusions (https://www.orfeo-toolbox.org/CookBook/Applications/app_Pansharpening.html).

But how can this affect our work?

Lets consider that I want to perform a pan-sharpening using this following images:

Using Orfeo toolbox I can achieve the following results: (Bayes, LMVM and RCS respectively)

Looking at the results made by Orfeo we can choose the RCS output as the best looking pan-sharpened image. In my opinion, it seems to get more details of that part of the land surrounded by water on top of the image, don’t you agree?

Now, the other 2, Bayes and LMVM outputs don’t look quite good in my humble opinion. The Bayes output delivered almost no change and the LMVM output seems a bit blurred.

Considering this, you can try to perform a pan-sharpening operation using HSV fusion, but this is not available neither in QGIS (natively) nor in Orfeo toolbox.

So, having that in mind, my co-workers and I decided to develop a script to perform pan-sharpening using HSV fusion. The result of our work is available as a tool in our QGIS plugin called DSG Tools (https://plugins.qgis.org/plugins/DsgTools/). In another another opportunity I will explain more about DSG Tools.

DSG Tools is a QGIS plugin developed by the Geographic Service at Brazilian Army. It was developed to make it possible to acquire vector data in QGIS in accordance to the Brazilian Geospatial Vector Data Structure, but besides that, DSG Tools provides a considerable toolbox that allow among other things, perform pan-sharpening using HSV fusion.

The script we made can be installed into QGIS’ toolbox and it will be available in a group called DSG as we can see next:

dsg_toolbox_group

Well, starting the script and setting its parameters (remember to superimpose the images prior the fusion – Orfeo has a tool for this) we can achieve the following result:

dsgtools_hsv_fusion

In my opinion, the pan-sharpened image generated by our HSV fusion script seems very close to the real terrain. Let’s now compare Orfeo’s RCS output and our HSV fusion output side by side:

Which one would you choose? I would choose the HSV fusion… But remember, this is just my opinion…

See you later! Bye!

Detecting duplicated geometries in a PostGIS table

Hi there!

Today I want to make a small post and talk about another annoying problem: Duplicated Geometries!

How can you identify which geometries are duplicated in your table? In some cases we have duplicated geometries with different attributes, which one is the correct one?

To deal with this, a simple query can help you in this matter.

Concepts to keep:

  • PARTITION BY: Is a window function that receives a column, this means it will partition the column in groups with equal values (this is what we want for our “geom” column: duplicates!)
  • ROW_NUMBER(): gives a row number, inside a partition, counting from 1. This means that any number greater than 1 is a duplicate.

Here it is:

select * from (
SELECT id, ROW_NUMBER() OVER(PARTITION BY geom ORDER BY id asc) AS Row,
geom FROM ONLY your_schema.your_table
) dups where dups.Row > 1

Now you can check the duplicates and choose which ones you want to keep.

That’s it!