Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature][expression] refFunction port to core #38405

Merged
merged 49 commits into from
Sep 11, 2020

Conversation

olivierdalang
Copy link
Contributor

@olivierdalang olivierdalang commented Aug 20, 2020

Description

This PR ports the refFunction plugin to core. RefFunctions are spatial operators expressions, allowing to make spatial queries on other layers from withing expressions, opening up a lot of really powerful workflows.

The hard work was done by @enricofer (the author of the plugin) and @m-kuhn , this is a rebase and polishing of their work.

reffunc2

The following new expression functions are implemented :

geometry_overlay_intersects(layer[,expression][,filter][,limit][,cache])
geometry_overlay_contains(layer[,expression][,filter][,limit][,cache])
geometry_overlay_crosses(layer[,expression][,filter][,limit][,cache])
geometry_overlay_equals(layer[,expression][,filter][,limit][,cache])
geometry_overlay_touches(layer[,expression][,filter][,limit][,cache])
geometry_overlay_disjoint(layer[,expression][,filter][,limit][,cache])
geometry_overlay_within(layer[,expression][,filter][,limit][,cache])
geometry_overlay_nearest(layer[,expression][,filter][,limit][,max_distance][,cache])

They all work in the same way : the spatial operator is evaluated against the other layer. If an expression is provided, it returns an array of results. If no expression is provided, it returns a boolean telling whether at least one feature matched.
Features can optionally be filtered by an expression, and optionally be limited to a certain count.

The geometry_overlay_nearest has an additional max_distance filter.

I'll leave this PR as a draft for some time as I still need to test it a little more and there's some more optimisation that can be done.

enricofer and others added 30 commits July 3, 2020 14:58
# Conflicts:
#	src/core/expression/qgsexpressionfunction.cpp
@qgis-bot
Copy link
Collaborator

@olivierdalang
This pull request has been tagged as requiring documentation.

A documentation ticket will be opened at https://github.com/qgis/QGIS-Documentation when this PR is merged.

Please update the description (not the comments) with helpful description and screenshot to help the work from documentors.
Also, any commit having [needs-doc] or [Needs Documentation] in will see its message pushed to the issue, so please be as verbose as you can.

Thank you!

@qgis-bot
Copy link
Collaborator

@olivierdalang
A documentation ticket has been opened at qgis/QGIS-Documentation#6102
It is your responsibility to visit this ticket and add as much detail as possible for the documentation team to correctly document this change.
Thank you!

@zacharlie zacharlie added ChangelogHarvested This PR description has been harvested in the Changelog already. and removed Changelog Items that are queued to appear in the visual changelog - remove after harvesting labels Sep 12, 2020
@olivierdalang olivierdalang deleted the refFunctionsRebase branch October 15, 2020 12:37
@M-Rick
Copy link

M-Rick commented Nov 13, 2020

I tried these new functions in QGIS 3.16, but they don't seem to work. I am needing to keep the refFunction plugin for now.
I tried to collect an attribute from a line layer to an intersecting point layer. At the beginning I used those brand new features, but I had no results at all. I thought my layers contained errors. But I then tried with refFunction and I got the expected results.
With the following refFunction expression it does work out of the box.
geomintersects('Line','Ref')
But when I switch to the new overlay functions it doesn't work.
I tried this expression instead of refFunction and it doesn't return me any results.
overlay_intersects('Line','Ref’)

Version de QGIS 3.16.0-Hannover Révision du code 4af1cbf
Compilé avec Qt 5.14.2 Utilisant Qt 5.14.2
Compilé avec GDAL/OGR 3.1.2 Utilisé avec GDAL/OGR 3.1.2
Compilé avec GEOS 3.8.1-CAPI-1.13.3 Utilisé avec GEOS 3.8.1-CAPI-1.13.3
Compilé avec SQLite 3.31.1 Fonctionne avec SQLite 3.31.1
Version du client PostgreSQL 12.3 Version de SpatiaLite 4.3.0a
Version de QWT 6.1.4 Version de QScintilla2 2.11.4
Compilé avec PROJ 6.3.2 Fonctionne avec PROJ Rel. 6.3.2, May 1st, 2020
Version de l'OS macOS 10.16
Extensions Python actives QuickOSM; processing_js; location_lab; refFunctions; qgis2web; qfieldsync; SgmExpressionFunctions; Mergin; processing; db_manager; MetaSearch

@olivierdalang
Copy link
Contributor Author

@M-Rick Thanks for reporting your issue !

Could you please open a new issue instead, so we can better keep track of it ? Also don't forget to add data and exact steps to reproduce the issue. Ping me in the issue (@olivierdalang) so I'll get a notification and look into it.

@DelazJ
Copy link
Contributor

DelazJ commented Nov 13, 2020

overlay_intersects('Line','Ref’)

This is not the correct syntax of the new function. It should be overlay_intersects('Line', Ref) assuming Ref is the field you want to collect data from. Not a QGIS issue IMHO.
See examples at https://docs.qgis.org/3.16/en/docs/user_manual/working_with_vector/functions_list.html#overlay-intersects Also keep in mind that it returns an array so either your destination field allows array type or you should add a conversion using array_to_string

@gioman
Copy link
Contributor

gioman commented Nov 13, 2020

This is not the correct syntax of the new function. It should be overlay_intersects('Line', Ref) assuming Ref is the field you want to collect data from. Not a QGIS issue IMHO.

@DelazJ after a quick test it does not seems to work anyway (the equivalent from the plugin works).

@DelazJ
Copy link
Contributor

DelazJ commented Nov 13, 2020

@gioman could you share the expression you tested and the context (ref comment above about array output), please?

@pigreco
Copy link
Sponsor Contributor

pigreco commented Nov 13, 2020

from a quick test to me it works:

image

OSGeo4W win 10 - QGIS 3.16 Hannover

@gioman
Copy link
Contributor

gioman commented Nov 13, 2020

from a quick test to me it works:

@pigreco with double quotes preview works, but then values are not saved to the target table/column.

@gioman
Copy link
Contributor

gioman commented Nov 13, 2020

@gioman could you share the expression you tested and the context (ref comment above about array output), please?

@DelazJ here it goes

exp_sample.zip

@pigreco
Copy link
Sponsor Contributor

pigreco commented Nov 13, 2020

@gioman

@pigreco with double quotes preview works, but then values are not saved to the target table/column.

it is normal because they are arrays, if you want to save them you have to define the new field as text and use the expression

array_to_string(
 overlay_intersects( 'Com01012020_g_WGS84',"comune")
 )

image

or if you just want an array value

overlay_intersects( 'Com01012020_g_WGS84',"comune")[0] → Barrafranca
overlay_intersects( 'Com01012020_g_WGS84',"comune")[1] → Villarosa
overlay_intersects( 'Com01012020_g_WGS84',"comune")[-1] → Enna

@gioman
Copy link
Contributor

gioman commented Nov 13, 2020

it is normal because they are arrays, if you want to save them you have to define the new field as text and use the expression

@pigreco ok I see. I little less convenient than the original function.

@DelazJ
Copy link
Contributor

DelazJ commented Nov 13, 2020

@pigreco with double quotes preview works,

@gioman Even without quotes, it works. The expression here is a field and as such can take double-quotes or not
image

@gioman
Copy link
Contributor

gioman commented Nov 13, 2020

@gioman Even without quotes, it works

@DelazJ I may be missing something, but it does not for me, unless using also "array_to_string" in the expression.

@DelazJ
Copy link
Contributor

DelazJ commented Nov 13, 2020

@gioman I meant "no need of quotes to have the expression return results. Ie, overlay_intersects( 'Com01012020_g_WGS84', "comune") is the same as overlay_intersects( 'Com01012020_g_WGS84', comune)."
But yes, if you want to store in a string field, you will always need the array_to_string function.

@gioman
Copy link
Contributor

gioman commented Nov 13, 2020

But yes, if you want to store in a string field, you will always need the array_to_string function.

actually I tried to extract a number and put it into a integer field, and it also do not work (also because extracting from polygons with points, so only 1 value is extracted).

@m-kuhn
Copy link
Member

m-kuhn commented Nov 13, 2020

Even if only 1 value is extracted it will be an array ([1]), it needs to be extracted with array_first(overlay_intersects( 'Com01012020_g_WGS84', comune)).

@gioman
Copy link
Contributor

gioman commented Nov 13, 2020

Even if only 1 value is extracted it will be an array ([1]), it needs to be extracted with array_first(overlay_intersects( 'Com01012020_g_WGS84', comune)).

ok. Should we add this in the function help?

@DelazJ
Copy link
Contributor

DelazJ commented Nov 13, 2020

I was also about to propose to add an example that returns comma separated list, as string. I think it's more common than the array_first case, and covers your use case here

acid_simbolo

@m-kuhn
Copy link
Member

m-kuhn commented Nov 13, 2020

Improving the function help would be very nice 👍

@gioman
Copy link
Contributor

gioman commented Nov 14, 2020

Improving the function help would be very nice +1

@m-kuhn after thinking about I'm not sure how is best to do that, after all is normal that in any function that returns an array, an array function must be used too... Maybe adding a general note if is not already there (can't find one, but docs are very large nowadays!)? @DelazJ

@m-kuhn
Copy link
Member

m-kuhn commented Nov 14, 2020

Maybe we could add it to the expression builder dialog, where we know it's an array (and we do some magic to convert it to a string already).

Hint: this expression returns an array, <a href="link/to/the/expression_array_doc">learn how to use arrays</a>

@gioman
Copy link
Contributor

gioman commented Nov 14, 2020

Maybe we could add it to the expression builder dialog, where we know it's an array (and we do some magic to convert it to a string already).

sounds good to me.

@DelazJ
Copy link
Contributor

DelazJ commented Nov 14, 2020

@gioman array functions are referenced at https://docs.qgis.org/testing/en/docs/user_manual/working_with_vector/functions_list.html#array-functions.
Adding the note as suggested by @m-kuhn sounds a good idea. In The docs, we currently display a url to reach array functions from the overlay functions (end of https://docs.qgis.org/testing/en/docs/user_manual/working_with_vector/functions_list.html#overlay-contains eg). We will probably remove them once this note is in place to avoid redundancy.
What I actually was suggesting in my previous comment is adding in the help panel an example of the type array_to_string( overlay_intersects( 'regions', "name")) that returns a comma separated list of values (and not array, as most of the current examples)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ChangelogHarvested This PR description has been harvested in the Changelog already. Expressions Related to the QGIS expression engine or specific expression functions Feature Needs Documentation When merging a labeled PR, an issue will be created in the Doc repo.
Projects
None yet
Development

Successfully merging this pull request may close these issues.