---
title: "Geometry interface and spatial measures"
author: "Alec L. Robitaille, Quinn Webber and Eric Vander Wal"
output: 
  rmarkdown::html_vignette:
    number_sections: true
    toc: true
vignette: >
  %\VignetteIndexEntry{Geometry interface and spatial measures}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  eval = TRUE,
  echo = TRUE,
  comment = "#>"
)
```

## Introduction

{spatsoc} v 0.2.13 provides a geometry interface and internal functions
that provide consistent spatial measures across all {spatsoc} functions.

The motivation for `get_geometry` is to allow users to supply a geometry
column instead of providing coordinates and optionally crs through the
"coords" and "crs" args. This interface is enabled by default on all
functions that accept coordinates / geometry, by leaving the coords null
and ensuring the geometry column has been set up using `get_geometry()`.

Details on spatial measures below under [Spatial measures].

------------------------------------------------------------------------

See the other vignettes for further information:

-   [Introduction to
    spatsoc](https://docs.ropensci.org/spatsoc/articles/intro.html)
    -   temporal grouping
    -   spatiotemporal grouping with `group_pts`, `group_lines`,
        `group_polys`
    -   distance based edge-list generation with `edge_dist`
-   [Frequently asked questions about
    spatsoc](https://docs.ropensci.org/spatsoc/articles/faq.html)
    -   install
    -   function details for `group_times`, `group_pts`, `group_lines`,
        `group_polys`, `edge_dist`, `edge_nn`, and `randomizations`
    -   package design including modify-by-reference, data.table column
        allocation
    -   calculating summary information
-   [Using spatsoc in social network
    analysis](https://docs.ropensci.org/spatsoc/articles/using-in-sna.html)
    -   generating gambit-of-the-group data
    -   generating observed networks
    -   data stream randomization, randomized networks
    -   network metrics
-   [Using distance based edge-lists generating functions, dyad_id, and
    fusion_id](https://docs.ropensci.org/spatsoc/articles/using-edge-and-dyad.html)
    -   generate distance based edge-lists with `edge_dist` and
        `edge_nn`
    -   generate dyad identifiers for edge-lists with `dyad_id`
    -   identify fusion events with `fusion_id`
-   [Geometry
    interface](https://docs.ropensci.org/spatsoc/articles/geometry-interface-and-spatial-measures.html)
    -   using `get_geometry` to setup a geometry column and use the
        geometry interface
    -   details of underlying distance, direction and centroid spatial
        measures
    -   converting to and from related packages
-   [Interspecific
    interactions](https://docs.ropensci.org/spatsoc/articles/interspecific-interactions.html)
    -   combine two movement datasets
    -   identify interspecific interactions

## Setup

Load packages

```{r}
library(spatsoc)
library(data.table)
```

Example data and variables

```{r}
# Read example data
DT <- fread(system.file('extdata', 'DT.csv', package = 'spatsoc'))

coords <- c('X', 'Y')
crs <- 32736
datetime <- 'datetime'
id <- 'ID'
```

## `get_geometry`

`get_geometry` can be used to setup a `DT` with a simple feature
geometry list column. Optionally, the input coordinates can be
transformed using the argument "output_crs". The default output geometry
column name can be changed using the argument "geometry_colname".

### Usage

```{r}
# Get geometry
get_geometry(DT, coords = coords, crs = crs)

print(DT)
```

## Spatial measures

### Distance

The underlying distance function used depends on the crs of the
coordinates or geometry provided.

-   If the crs is longlat degrees (as determined by
    `sf::st_is_longlat()`), the distance function is `sf::st_distance()`
    which passes to `s2::s2_distance()` if `sf::sf_use_s2()` is TRUE and
    `lwgeom::st_geod_distance()` if `sf::sf_use_s2()` is FALSE. The
    distance returned has units set according to the crs.

-   If the crs is not longlat degrees (eg. NULL, `NA_crs_`, or
    projected), the distance function used is `stats::dist()`,
    maintaining expected behaviour from previous versions. The distance
    returned does not have units set.

Note: in both cases, if the coordinates are NA then the result will be
NA.

### Direction

The underlying distance function used depends on the crs of the
coordinates or geometry provided.

-   If the crs is provided and longlat degrees (as determined by
    `sf::st_is_longlat()`), the distance function is
    `lwgeom::st_geod_azimuth()`.

-   If the crs is provided and not longlat degrees (eg. a projected
    UTM), the coordinates or geometry are transformed to
    `sf::st_crs(4326)` before the distance is measured using
    `lwgeom::st_geod_azimuth()`.

-   If the crs is NULL or `NA_crs_`, the distance function cannot be
    used and an error is returned.

The crs for direction functions (eg. `direction_step`,
`direction_to_centroid`) should be either longlat or a crs that can be
transformed to `sf::st_crs(4326)`. A user can check their crs by using
the function `sf::st_can_transform(src = crs, dst = 4326)`.

If a user provides a crs that is not longlat and cannot be transformed
to 4326, they will receive an internal error with the following
structure:

`"In CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, : GDAL Error 6: Cannot find coordinate operations from..."`

### Centroid

The underlying centroid function used depends on the crs of the
coordinates or geometry provided.

-   If the crs is longlat degrees (as determined by
    `sf::st_is_longlat()`) and `sf::sf_use_s2()` is TRUE, the distance
    function is `sf::st_centroid()` which passes to `s2::s2_centroid()`.

-   If the crs is longlat degrees but `sf::sf_use_s2()` is FALSE, the
    centroid calculated will be incorrect. See `sf::st_centroid()`.

-   If the crs is not longlat degrees (eg. NULL, NA_crs\_, or
    projected), the centroid function used is mean.

Note: if the input is length 1, the input is returned directly without
any processing.

The `distance_to_centroid`, `direction_to_centroid` and
`leader_direction_group` expect a centroid column named 'centroid' when
the geometry interface is used. Ensure the `centroid_group` function has
been used with the geometry interface before running these functions.

The following warning may be returned when centroid functions are used
with longlat coordinates / geometry and the {s2} package is not
available or `sf::sf_use_s2()` is `FALSE`. Please set
`sf::sf_use_s2(TRUE)` and try again.

## Converting from other packages

Instead of using `get_geometry()`, coming from other packages, we can
convert the objects to data.tables for processing with {spatsoc}.
Caution: {spatsoc}'s expectation is that the "geometry" column is
`sfc_POINT` representing each relocation.

### Converting from {sftrack}

```{r}
library(sftrack)
data("raccoon")
raccoon$timestamp <- as.POSIXct(raccoon$timestamp, "EST")
burstz <- list(id = raccoon$animal_id, month = as.POSIXlt(raccoon$timestamp)$mon)
my_track <- as_sftrack(raccoon,
  group = burstz, time = "timestamp",
  error = NA, coords = c("longitude", "latitude")
)

DT_sftrack <- as.data.table(my_track)

print(DT_sftrack)
```

### Converting from {move2}

```{r}
library(move2)
fishers <- mt_read(mt_example(file = "fishers.csv.gz"))
DT_move2 <- as.data.table(fishers)

print(DT_move2)
```

## Converting to other packages

After processing with {spatsoc}, optionally convert output to work with
other packages. Caution: {spatsoc}'s expectation is that users take
their input data.table through any required functions in {spatsoc}
before converting to other packages or using eg. {dplyr}. Intermixing
packages between {spatsoc} functions can lead to issues with
{data.table} class or column allocation. See more details under Package
Design in [FAQ](https://docs.ropensci.org/spatsoc/articles/faq.html).

An example of a potential issue with intermixing packages between
spatsoc functions is that attributes such as the sf column's bbox aren't
automatically updated when subsetting with data.table. This impacts the
bbox returned, and also the bbox used for plotting. The recommendation
is to run all required {spatsoc} functions then convert to standard
spatial formats as described below for further processing and
visualization.

```{r}
library(sf)
DT[, st_bbox(geometry)]
DT[1:10, st_bbox(geometry)]

DT[, plot(geometry)]
DT[1:10, plot(geometry)]

# Note the bbox can also be manually recomputed
DT[1:10, st_bbox(st_sfc(geometry, recompute_bbox = TRUE))]
DT[1:10, plot(st_sfc(geometry, recompute_bbox = TRUE))]
```

### Converting to {sf}

```{r}
DT_sf <- st_as_sf(DT, sf_column_name = 'geometry')
print(DT_sf)
plot(DT_sf)
```

### Converting to {sftrack}

```{r}
library(sftrack)

# First convert to sf as above
DT_sf <- st_as_sf(DT, sf_column_name = 'geometry')
# Then convert to sftrack
DT_sftrack <- as_sftrack(DT_sf, group = c(id = id), time = datetime)

head(DT_sftrack)
plot(DT_sftrack)
```

### Converting to {move2}

```{r}
library(move2)

# Convert to a {move2} object using mt_as_move2
DT_move2 <- mt_as_move2(DT,
  time_column = datetime,
  track_id_column = id,
  sf_column_name = 'geometry'
)

print(DT_move2)
plot(DT_move2)
```
