---
title: "prepr: Automatic Repair of Spatial Polygons"
output:
  rmarkdown::html_vignette:
    toc: true
    fig_caption: true
fontsize: 11pt
documentclass: article
vignette: >
  %\VignetteIndexEntry{prepr: Automatic Repair of Spatial Polygons}
  %\VignetteEngine{knitr::rmarkdown_notangle}
---

```{r, include = FALSE}
# define variables for vignette figures and code execution
h <- 4.0
w <- 7.0
is_check <-
  ("CheckExEnv" %in% search()) ||
  any(c("_R_CHECK_TIMINGS_", "_R_CHECK_LICENSE_") %in% names(Sys.getenv())) ||
  !identical(Sys.getenv("MY_UNIVERSE"), "")
knitr::opts_chunk$set(
  fig.align = "center",
  eval = !is_check,
  purl = !is_check,
  R.options = list(width = 80)
)
```

## Introduction

The _prepr R_ R package is used to repair broken spatial polygons. To achieve this, the package uses the constrained triangulation approach implemented in the [`prepair`](https://github.com/tudelft3d/prepair) C++ library ([Ledoux et al. 2014](https://doi.org/10.1016/j.cageo.2014.01.009)). Specifically, the main `st_prepair()` function is used to repair polygons.

## Tutorial

Here we provide a short tutorial showing how the _prepr_ package can be used to repair broken polygon geometries. To start with, we will load the package. We will also load the _sf_ package for working with spatial data.

```{r, message = FALSE}
# load packages
library(sf)    # package for working with spatial data
library(prepr) # package for repairing spatial geometries
```

We will now show how the _prepr_ package can be used to repair broken geometries. To achieve this, we will examine a range of different mechanisms by which polygons can be broken. For each of these mechanisms, we will manually create a broken polygon geometry based on the mechanism, repair the geometry (using `st_prepair()`), and then compare the repaired geometry with the original broken geometry. We will also confirm that the broken geometries have indeed been repaired (using `sf::st_is_valid()`).

### A 'bowtie' polygon

```{r example1}
# create broken polygon
x <- st_as_sfc("POLYGON((0 0, 0 10, 10 0, 10 10, 0 0))")

# verify that polygon is broken, and display reason why it's broken
st_is_valid(x, reason = TRUE)

# repair the polygon
y <- st_prepair(x)

# verify that repaired polygon is NOT broken
st_is_valid(y)

# visualize the polygons
par(mfrow = c(1, 2), mar = c(0, 0, 2.5, 0))
plot(x, main = "original", col = "#999999")
points(st_coordinates(st_cast(x, "POINT")), col = "#e41a1c", pch = 16, cex = 2)
plot(y, main = "repaired", col = "#999999")
points(st_coordinates(st_cast(y, "POINT")), col = "#e41a1c", pch = 16, cex = 2)
```

### Square with wrong orientation

```{r example2}
# create broken polygon
x <- st_as_sfc("POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))")

# verify that polygon is broken, and display reason why it's broken
st_is_valid(x, reason = TRUE)

# repair the polygon
y <- st_prepair(x)

# verify that repaired polygon is NOT broken
st_is_valid(y)

# visualize the polygons
par(mfrow = c(1, 2), mar = c(0, 0, 2.5, 0))
plot(x, main = "original", col = "#999999")
points(st_coordinates(st_cast(x, "POINT")), col = "#e41a1c", pch = 16, cex = 2)
plot(y, main = "repaired", col = "#999999")
points(st_coordinates(st_cast(y, "POINT")), col = "#e41a1c", pch = 16, cex = 2)
```

### Inner ring with one edge sharing part of an edge of the outer ring

```{r example3}
# create broken polygon
x <- st_as_sfc(
  "POLYGON((0 0, 10 0, 10 10, 0 10, 0 0),(5 2, 5 7, 10 7, 10 2, 5 2))"
)

# verify that polygon is broken, and display reason why it's broken
st_is_valid(x, reason = TRUE)

# repair the polygon
y <- st_prepair(x)

# verify that repaired polygon is NOT broken
st_is_valid(y)

# visualize the polygons
par(mfrow = c(1, 2), mar = c(0, 0, 2.5, 0))
plot(x, main = "original", col = "#999999")
points(st_coordinates(st_cast(x, "POINT")), col = "#e41a1c", pch = 16, cex = 2)
plot(y, main = "repaired", col = "#999999")
points(st_coordinates(st_cast(y, "POINT")), col = "#e41a1c", pch = 16, cex = 2)
```

### Dangling edge

```{r example4}
# create broken polygon
x <- st_as_sfc("POLYGON((0 0, 10 0, 15 5, 10 0, 10 10, 0 10, 0 0))")

# verify that polygon is broken, and display reason why it's broken
st_is_valid(x, reason = TRUE)

# repair the polygon
y <- st_prepair(x)

# verify that repaired polygon is NOT broken
st_is_valid(y)

# visualize the polygons
par(mfrow = c(1, 2), mar = c(0, 0, 2.5, 0))
plot(x, main = "original", col = "#999999")
points(st_coordinates(st_cast(x, "POINT")), col = "#e41a1c", pch = 16, cex = 2)
plot(y, main = "repaired", col = "#999999")
points(st_coordinates(st_cast(y, "POINT")), col = "#e41a1c", pch = 16, cex = 2)
```

### Two adjacent inner rings

```{r example5}
# create broken polygon
x <- st_as_sfc(
  paste(
    "POLYGON((0 0, 10 0, 10 10, 0 10, 0 0),",
    "(1 1, 1 8, 3 8, 3 1, 1 1), (3 1, 3 8, 5 8, 5 1, 3 1))"
  )
)

# verify that polygon is broken, and display reason why it's broken
st_is_valid(x, reason = TRUE)

# repair the polygon
y <- st_prepair(x)

# verify that repaired polygon is NOT broken
st_is_valid(y)

# visualize the polygons
par(mfrow = c(1, 2), mar = c(0, 0, 2.5, 0))
plot(x, main = "original", col = "#999999")
points(st_coordinates(st_cast(x, "POINT")), col = "#e41a1c", pch = 16, cex = 2)
plot(y, main = "repaired", col = "#999999")
points(st_coordinates(st_cast(y, "POINT")), col = "#e41a1c", pch = 16, cex = 2)
```

### Polygon with an inner ring inside another inner ring

```{r example6}
# create broken polygon
x <- st_as_sfc(
  paste(
    "POLYGON((0 0, 10 0, 10 10, 0 10, 0 0),",
    "(2 8, 5 8, 5 2, 2 2, 2 8), (3 3, 4 3, 3 4, 3 3))"
  )
)

# verify that polygon is broken, and display reason why it's broken
st_is_valid(x, reason = TRUE)

# repair the polygon
y <- st_prepair(x)

# verify that repaired polygon is NOT broken
st_is_valid(y)

# visualize the polygons
par(mfrow = c(1, 2), mar = c(0, 0, 2.5, 0))
plot(x, main = "original", col = "#999999")
points(st_coordinates(st_cast(x, "POINT")), col = "#e41a1c", pch = 16, cex = 2)
plot(y, main = "repaired", col = "#999999")
points(st_coordinates(st_cast(y, "POINT")), col = "#e41a1c", pch = 16, cex = 2)
```

## Citation

We recommend citing the methodology that underpins the _prepr R_ package. To cite this work, please use:

> Ledoux H, Arroyo Ohori K, and Meijers M (2014) A triangulation-based approach to automatically repair GIS polygons. *Computers & Geosciences* 66:121--131.

## Getting help

If you have any questions about using the _prepr R_ package or suggestions for improving it, please [file an issue at the package's online code repository](https://github.com/prioritizr/prepr/issues/new).
