# Simple feature support

A common way to deal with spatial data in R is the sf package, which is built on the concept of simple features. According to the the sf package vignette, simple features are “…a formal standard (ISO 19125-1:2004) that describes how objects in the real world can be represented in computers, with emphasis on the spatial geometry of these objects. It also describes how such objects can be stored in and retrieved from databases, and which geometrical operations should be defined for them.”

The most common geometry types of simple features are: POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, MULTIPOLYGON. All geometry types are based on POINTs. This package supports the encoding and decoding of the geometry types POINT, LINESTRING and POLYGON.

There are four possible dimension combinations of geometries in the sf package. In the `flexpolyine` package the first three dimension combinations are supported and represented as follows:

- XY: Represented as line with LNG and LAT dimensions.
- XYZ: Represented as line with LNG, LAT and LEVEL/ALTITUDE/ELEVATION as third dimension.
- XYM: Represented as line with LNG, LAT and CUSTOM1/CUSTOM2 as third dimension.
- XYZM: Not supported.

## Encoding and decoding

### Simple feature geometry (sfg)

If no value for `third_dim` is provided in `encode_sf()`, the dimensions of the sf geometry are considered. In case of `"XYZ"` the third dimension is set to `"ELEVATION"` and thereby recognized again as `"XYZ"` by `decode_sf()` during decoding:

    library(flexpolyline)
    library(sf)
    #> Linking to GEOS 3.8.1, GDAL 3.2.1, PROJ 7.2.1

    coords <- matrix(
        c(8.69821, 50.10228, 10.11111,
          8.69567, 50.10201, 20.22222,
          8.69150, 50.10063, 30.33333,
          8.68752, 50.09878, 40.44444),
        ncol = 3, byrow = TRUE
    )

    (sfg_z <- st_linestring(coords, dim = "XYZ"))
    #> LINESTRING Z (8.69821 50.10228 10.11111, 8.69567 50.10201 20.22222, 8.6915 50.10063 30.33333, 8.68752 50.09878 40.44444)

    (sfg_enc_z <- encode_sf(sfg_z))
    #> [1] "B1Voz5xJ67i1Bu629B1B7Pu629BzIhau629BxL7Yu629B"

    decode_sf(sfg_enc_z)
    #> Simple feature collection with 1 feature and 2 fields
    #> Geometry type: LINESTRING
    #> Dimension:     XYZ
    #> Bounding box:  xmin: 8.68752 ymin: 50.09878 xmax: 8.69821 ymax: 50.10228
    #> z_range:       zmin: 10.11111 zmax: 40.44444
    #> CRS:           NA
    #>   id      dim3                       geometry
    #> 1  1 ELEVATION LINESTRING Z (8.69821 50.10...

In case of `"XYM"` the third dimension is set to `"CUSTOM1"` and again set to `"XYM"` in decoding:

    (sfg_m <- st_linestring(coords, dim = "XYM"))
    #> LINESTRING M (8.69821 50.10228 10.11111, 8.69567 50.10201 20.22222, 8.6915 50.10063 30.33333, 8.68752 50.09878 40.44444)

    (sfg_enc_m <- encode_sf(sfg_m))
    #> [1] "BlXoz5xJ67i1Bu629B1B7Pu629BzIhau629BxL7Yu629B"

    decode_sf(sfg_enc_m)
    #> Simple feature collection with 1 feature and 2 fields
    #> Geometry type: LINESTRING
    #> Dimension:     XYM
    #> Bounding box:  xmin: 8.68752 ymin: 50.09878 xmax: 8.69821 ymax: 50.10228
    #> m_range:       mmin: 10.11111 mmax: 40.44444
    #> CRS:           NA
    #>   id    dim3                       geometry
    #> 1  1 CUSTOM1 LINESTRING M (8.69821 50.10...

### Simple feature geometry list-column (sfc)

The geometry column in simple feature data sets is called simple feature geometry list-column. The sfc object has a Coordinate Reference System (CRS) assigned. In the case of longitude and latitude data this is most often WGS84 (EPSG: 4326). Objects of type `sfc` are supported as input in encoding:

    (sfc <- st_as_sfc(
      lapply(seq(1, 5), function(x) {
        st_linestring(coords[, 1:2] + runif(1, -1, 1), dim = "XY")
      }),
      crs = 4326
    ))
    #> Geometry set for 5 features
    #> Geometry type: LINESTRING
    #> Dimension:     XY
    #> Bounding box:  xmin: 7.688635 ymin: 49.09989 xmax: 9.40586 ymax: 50.80993
    #> Geodetic CRS:  WGS 84
    #> LINESTRING (9.13392 50.53799, 9.13138 50.53772,...
    #> LINESTRING (9.40586 50.80993, 9.40332 50.80966,...
    #> LINESTRING (8.599163 50.00323, 8.596623 50.0029...
    #> LINESTRING (8.310973 49.71504, 8.308433 49.7147...
    #> LINESTRING (7.699325 49.10339, 7.696785 49.1031...

    (sfc_enc <- encode_sf(sfc))
    #> [1] "BFu2u0Jg_33B1B7PzIhaxL7Y" "BFi6j2J0it5B1B7PzIhaxL7Y"
    #> [3] "BFmomxJ4wv0B1B7PzIhaxL7Y" "BFg_tvJyn3yB1B7PzIhaxL7Y"
    #> [5] "BFmw2rJ44_uB1B7PzIhaxL7Y"

    decode_sf(sfc_enc, crs = 4326)
    #> Simple feature collection with 5 features and 2 fields
    #> Geometry type: LINESTRING
    #> Dimension:     XY
    #> Bounding box:  xmin: 7.68863 ymin: 49.09989 xmax: 9.40586 ymax: 50.80993
    #> Geodetic CRS:  WGS 84
    #>   id   dim3                       geometry
    #> 1  1 ABSENT LINESTRING (9.13392 50.5379...
    #> 2  2 ABSENT LINESTRING (9.40586 50.8099...
    #> 3  3 ABSENT LINESTRING (8.59916 50.0032...
    #> 4  4 ABSENT LINESTRING (8.31097 49.7150...
    #> 5  5 ABSENT LINESTRING (7.69932 49.1033...

### Simple feature (sf)

A simple feature is a geometry that is connected with further characteristics (other than it’s coordinates), which in practice means a `data.frame` (also `data.table` or `tibble`) with an `sfc` column. The flexpolyline package only takes care of the coordinates of the LINESTRINGs in the sf object, other columns and the CRS information are not encoded and stored in the string:

    (sf <- st_as_sf(
      data.frame(
        name = c("A", "B", "C", "D", "E"),
        color = sample(c("red", "green", "blue"), 5, replace = TRUE),
        geometry = sfc
      )
    ))
    #> Simple feature collection with 5 features and 2 fields
    #> Geometry type: LINESTRING
    #> Dimension:     XY
    #> Bounding box:  xmin: 7.688635 ymin: 49.09989 xmax: 9.40586 ymax: 50.80993
    #> Geodetic CRS:  WGS 84
    #>   name color                       geometry
    #> 1    A  blue LINESTRING (9.13392 50.5379...
    #> 2    B green LINESTRING (9.40586 50.8099...
    #> 3    C green LINESTRING (8.599163 50.003...
    #> 4    D  blue LINESTRING (8.310973 49.715...
    #> 5    E  blue LINESTRING (7.699325 49.103...

    (sf_enc <- encode_sf(sf))
    #> [1] "BFu2u0Jg_33B1B7PzIhaxL7Y" "BFi6j2J0it5B1B7PzIhaxL7Y"
    #> [3] "BFmomxJ4wv0B1B7PzIhaxL7Y" "BFg_tvJyn3yB1B7PzIhaxL7Y"
    #> [5] "BFmw2rJ44_uB1B7PzIhaxL7Y"

    decode_sf(sf_enc, crs = 4326)
    #> Simple feature collection with 5 features and 2 fields
    #> Geometry type: LINESTRING
    #> Dimension:     XY
    #> Bounding box:  xmin: 7.68863 ymin: 49.09989 xmax: 9.40586 ymax: 50.80993
    #> Geodetic CRS:  WGS 84
    #>   id   dim3                       geometry
    #> 1  1 ABSENT LINESTRING (9.13392 50.5379...
    #> 2  2 ABSENT LINESTRING (9.40586 50.8099...
    #> 3  3 ABSENT LINESTRING (8.59916 50.0032...
    #> 4  4 ABSENT LINESTRING (8.31097 49.7150...
    #> 5  5 ABSENT LINESTRING (7.69932 49.1033...

Note: The columns `"name"` and `"color"` were not encoded and are missing after decoding. The CRS has to be provided in the decoding by the `crs` argument. Otherwise it is set to `sf::NA_crs_`.

## References

- CRAN: Simple Features for R
- Wikipedia: Simple Features
- OGC: Simple Feature Access