```{r setup, message=FALSE}
library(qgisprocess)
library(sf)
```

# Introduction

Many QGIS processing algorithms provide the possibility to use [QGIS expressions](https://docs.qgis.org/latest/en/docs/user_manual/expressions/index.html).
If an algorithm argument expects a QGIS expression, this is typically marked by a button in the QGIS processing dialog that opens the QGIS expression builder (e.g. in `native:extractbyexpression`), or by a directly integrated QGIS expression builder (e.g. in `native:fieldcalculator`).
Such arguments are of type `expression`, as seen in the output of `qgis_get_argument_specs()`.
  
```{r}
qgis_get_argument_specs("native:fieldcalculator") |> subset(name == "FORMULA")
```

Secondly, one can use expressions for _data-defined_ overriding.
This means that an algorithm argument that is usually a fixed value (number, distance, boolean, string or color) can _also_ take on the value of another field or the result of an expression.
In the QGIS processing dialog, such arguments have a '[data-defined override](https://docs.qgis.org/latest/en/docs/user_manual/introduction/general_tools.html#data-defined)' button.
An example is provided by the `DISTANCE` argument of `native:buffer`, for which we query the acceptable values below.

```{r}
qgis_get_argument_specs("native:buffer") |> 
  subset(name == "DISTANCE", acceptable_values) |> 
  tidyr::unnest_longer(acceptable_values) |> 
  knitr::kable()
```

# Examples where the argument expects a QGIS expression

As example data, we use a lake polygon and a set of points that have lake depth as attribute.

```{r}
longlake_path <- system.file("longlake/longlake.gpkg", package = "qgisprocess")
longlake_depth_path <- system.file("longlake/longlake_depth.gpkg", package = "qgisprocess")
```

```{r}
nrow(read_sf(longlake_depth_path))
```

In a first example, we use a QGIS expression to filter points by depth.
We can simply pass the expression as a string:

```{r}
qgis_run_algorithm(
  "native:extractbyexpression",
  INPUT = longlake_depth_path,
  EXPRESSION = '"DEPTH_M" > 1'
) |>
  st_as_sf()
```

More often, you will want to use QGIS functions in expressions, and look at the relationship between geometries or create new geometries.

Let's calculate the distance between the points and the lake border, and add it as an attribute to the points.
For that we will use the `native:fieldcalculator` algorithm.

We first create the lake border:

```{r}
lake_border_path <- qgis_run_algorithm(
  "native:polygonstolines", 
  INPUT = longlake_path
) |> 
  qgis_extract_output("OUTPUT")
```

Next, build the QGIS expression.
Referring to the `INPUT` geometry in `native:fieldcalculator` is done with the `@geometry` variable.

```{r}
expr <- glue::glue("distance(
                     @geometry, 
                     geometry(
                       get_feature_by_id(
                         load_layer('{lake_border_path}', 'ogr'), 
                         1
                       )
                     )
                    )")
```

Referring to the lake border geometry in an expression is a bit trickier, since it requires several QGIS functions.
The layer can be loaded from a filepath with the `load_layer()` function, then the first (and only) feature is selected with `get_feature_by_id()`, and the geometry of that feature is selected using the `geometry()` function.
These steps are needed because the `distance()` function needs geometries to work on, not features, layers or filepaths.

Use the QGIS expression builder to look up function documentation, or consult the online [QGIS function documentation](https://docs.qgis.org/latest/en/docs/user_manual/expressions/functions_list.html).

Note: the `load_layer()` function is only available since QGIS 3.30.0!
In earlier versions, you needed to refer to the layer's name in an _existing_ QGIS project, and refer to the project path in `qgis_run_algorithm()` with the special `PROJECT_PATH` argument.
The `load_layer()` approach since QGIS 3.30.0 avoids the need for a QGIS project.

Now we can run the algorithm:

```{r eval=!qgisprocess:::is_windows()}
qgis_run_algorithm(
  "native:fieldcalculator",
  INPUT = longlake_depth_path,
  FIELD_NAME = "distance",
  FORMULA = expr
) |> 
  st_as_sf()
```

# Example applying a data-defined override

Suppose that we want to create a buffer around the points with a dynamic radius expressed as a function of `DEPTH_M`, e.g. 10 times the depth at each point.
We will use `native:buffer` for that purpose.
Note: applying a data-defined override with **qgisprocess** is only possible since QGIS 3.30.0!

Because `DISTANCE` by default expects a numeric value, you have to use the prefix `expression:` if you want to pass an expression string.
Double quotes are used in QGIS expressions to denote fields (attributes), but you can also omit them.

Let's try:

```{r}
buffer <- qgis_run_algorithm(
  "native:buffer",
  INPUT = longlake_depth_path,
  DISTANCE = 'expression: "DEPTH_M" * 10'
) |> 
  st_as_sf()
```

So from the `r nrow(buffer)` points we have created `r nrow(buffer)` polygons:

```{r}
st_geometry_type(buffer) |> as.character() |> table()
```

Plot the result:

```{r}
oldpar <- par(mar = rep(0.1, 4))
plot(read_sf(lake_border_path) |> st_geometry())
plot(buffer[, "DEPTH_M"], add = TRUE)
par(oldpar)
```

If you just want to refer to the value of another attribute, then you can also use the `field:` prefix instead, _without_ double quotes around the attribute name and _without_ spaces:

```{r eval=FALSE}
qgis_run_algorithm(
  "native:buffer",
  INPUT = longlake_depth_path,
  DISTANCE = "field:DEPTH_M"
) |> 
  st_as_sf()
```



