#' @rdname Geom
#' @format NULL
#' @usage NULL
#' @export
GeomHex <- ggproto("GeomHex", Geom,
  draw_group = function(self, data, panel_params, coord, lineend = "butt",
                        linejoin = "mitre", linemitre = 10) {
    data <- fix_linewidth(data, snake_class(self))
    if (empty(data)) {
      return(zeroGrob())
    }

    # Get hex sizes
    if (!is.null(data$width)) {
      dx <- data$width[1] / 2
    } else {
      dx <- resolution(data$x, FALSE, TRUE)
    }
    # Adjust for difference in width and height of regular hexagon. 1.15 adjusts
    # for the effect of the overlapping range in y-direction on the resolution
    # calculation
    if (!is.null(data$height)) {
      dy <- data$height[1] /  sqrt(3) / 2
    } else {
      dy <- resolution(data$y, FALSE, TRUE) / sqrt(3) / 2 * 1.15
    }

    hexC <- hexbin::hexcoords(dx, dy, n = 1)

    n <- nrow(data)

    hexdata <- data[rep(seq_len(n), each = 6), c("x", "y")]
    hexdata$x <- rep.int(hexC$x, n) + hexdata$x
    hexdata$y <- rep.int(hexC$y, n) + hexdata$y

    coords <- coord$transform(hexdata, panel_params)

    ggname("geom_hex", polygonGrob(
      coords$x, coords$y,
      gp = gg_par(
        col = data$colour,
        fill = fill_alpha(data$fill, data$alpha),
        lwd = data$linewidth,
        lty = data$linetype,
        lineend = lineend,
        linejoin = linejoin,
        linemitre = linemitre
      ),
      default.units = "native",
      id.lengths = rep.int(6, n)
    ))
  },

  required_aes = c("x", "y"),

  default_aes = aes(
    colour = from_theme(colour %||% NA),
    fill = from_theme(fill %||% col_mix(ink, paper)),
    linewidth = from_theme(borderwidth),
    linetype = from_theme(bordertype),
    alpha = NA
  ),

  draw_key = draw_key_polygon,

  rename_size = TRUE
)

#' Hexagonal heatmap of 2d bin counts
#'
#' Divides the plane into regular hexagons, counts the number of cases in
#' each hexagon, and then (by default) maps the number of cases to the hexagon
#' fill.  Hexagon bins avoid the visual artefacts sometimes generated by
#' the very regular alignment of [geom_bin_2d()].
#'
#' @aesthetics GeomHex
#' @aesthetics StatBinhex
#' @seealso [stat_bin_2d()] for rectangular binning
#' @param geom,stat Override the default connection between `geom_hex()` and
#'   `stat_bin_hex()`. For more information about overriding these connections,
#'   see how the [stat][layer_stats] and [geom][layer_geoms] arguments work.
#' @export
#' @inheritParams layer
#' @inheritParams geom_point
#' @param lineend Line end style (round, butt, square).
#' @param linejoin Line join style (round, mitre, bevel).
#' @param linemitre Line mitre limit (number greater than 1).
#' @export
#' @examples
#' d <- ggplot(diamonds, aes(carat, price))
#' d + geom_hex()
#'
#' \donttest{
#' # You can control the size of the bins by specifying the number of
#' # bins in each direction:
#' d + geom_hex(bins = 10)
#' d + geom_hex(bins = 30)
#'
#' # Or by specifying the width of the bins
#' d + geom_hex(binwidth = c(1, 1000))
#' d + geom_hex(binwidth = c(.1, 500))
#' }
geom_hex <- make_constructor(GeomHex, stat = 'binhex')
