#' @title Plot a sf or sfc object with hatching
#'
#' @details
#' The function makes a call to `polygon()` after some transformations of the sf
#' (or sfc) object. It will plot something only if all geometry types of x are
#' 'MULTIPOLYGON'. In the other case, it will just send a warning.
#' 
#' All rendering parameters can be set for original number of features. More
#' details are to be found in `polygon()` help.
#'
#' @param x sf or sfc object
#' @param density numeric, the density of shading lines, in lines per inch.
#' @param angle numeric, the slope of shading lines, given as an angle in degrees
#'  (counter-clockwise).
#' @param col character, the color of the shading lines.
#' @param border character, the color to draw the border. 
#'
#' @return Nothing useful.
#'
#' @export plot_density
#'
#' @encoding UTF-8
#'
#' @examples
#'
#' map_so_ii()
#' plot_density(so_ii_collectivity)
#' plot_density(
#'  so_ii_collectivity,
#'  density = c(10,20),
#'  col = c("black", "blue", "green"),
#'  border = "gray",
#'  angle = seq(nrow(so_ii_collectivity))
#' )

plot_density = function(x, density = NULL, angle = 45, col = NA, border = NULL) {
    geometry_type = as.character(sf::st_geometry_type(x))
    if (! all(geometry_type %in% "MULTIPOLYGON" )) {
        warnings("geometry type of x is not of 'MULTIPOLYGON', nothing is plotted.")
        return(invisible())
    }

    n_polygon = length(geometry_type)
    if (!is.null(density) && length(density) != n_polygon) density = rep(density, length.out = n_polygon)
    if (length(angle) != n_polygon) angle = rep(angle, length.out = n_polygon)
    if (length(col) != n_polygon) col = rep(col, length.out = n_polygon)
    if (!is.null(border) && length(border) != n_polygon) border = rep(border, length.out = n_polygon)

    mat = as.data.frame(sf::st_coordinates(x))
    names(mat) = tolower(names(mat))
    mat = split(as.data.frame(mat), paste(mat[["l2"]], mat[["l3"]]))
    id = as.integer(sapply(strsplit(names(mat), " "), `[`, 2))
    mat = lapply(mat, function(x){rbind(x, NA)})

    mat = do.call(rbind, mat)
    if (!is.null(density)) density = density[id]
    angle = angle[as.integer(id)]
    col = col[as.integer(id)]
    if (!is.null(border)) border = border[id]
    if (all(is.na(border))) border = NA

    graphics::polygon(mat, density = density, angle = angle, border = border, col = col)
    return(invisible())
}
