R/star_scale.R

Defines functions dist internal_to_external external_to_internal star_angle2 star_angle star_scale2 star_scale

Documented in star_angle star_scale

#' Compute regular star polygon scale or angles
#'
#' `star_scale()` computes star `scale` value given
#' an internal or external angle.  `star_angle()` computes
#' star angle (internal or external) given a `scale` value.
#'
#' [grid.pattern_regular_polygon()] parameterizes regular star polygons
#' with the number of its external vertices and a `scale` that equals the
#' fraction of the radius of the circle that circumscribes the interior vertices
#' divided by the radius of the circle that circumscribes the exterior vertices.
#' These helper functions help convert between that parameterization
#' and either the internal or external angle of the regular star polygon.
#' @param n_vertices Number of exterior vertices.
#' @param angle Angle in degrees.
#' @param scale Scale from 0 to 1.
#' @param external If `TRUE` angle should be considered an external angle.
#' @return `star_scale()` returns a numeric value between 0 and 1 intended
#'         for use as the `scale` argument in [grid.pattern_regular_polygon()].
#'         `star_angle()` returns a numeric value between 0 and 360 (degrees).
#' @examples
#'   # |8/3| star has internal angle 45 degrees and external angle 90 degrees
#'   scale <- star_scale(8, 45)
#'   scale2 <- star_scale(8, 90, external = TRUE)
#'   all.equal(scale, scale2)
#'   star_angle(8, scale)
#'   star_angle(8, scale, external = TRUE)
#'
#'   if (require("grid")) {
#'     grid.pattern_regular_polygon(shape = "star8", scale = scale, angle = 0,
#'                                  spacing = 0.2, density = 0.8)
#'   }
#'
#' @export
star_scale <- function(n_vertices, angle, external = FALSE) {
    if (external)
        angle <- external_to_internal(n_vertices, angle)
    if (n_vertices == 2)
        return(star_scale2(angle))
    stopifnot(angle >= 0, angle <= 180 * (1 - 2/n_vertices))
    # we'll work with external degree
    angle <- internal_to_external(n_vertices, angle)
    t <- 360 / n_vertices
    xy1 <- list(x = 1, y = 0)
    xy2 <- list(x = to_x(t, 1), y = to_y(t, 1))
    xyc <- list(x = mean(c(xy1$x, xy2$x)), y = mean(c(xy1$y, xy2$y)))
    xyf <- list(x = to_x(t/2, 1), y = to_y(t/2, 1))
    dist_f <- dist(xyf, xyc)
    a2 <- dist(xy1, xyc)
    beta <- (180 - angle) / 2
    b <- a2 * sin(to_radians(beta)) / sin(to_radians(angle/2))
    r <- 1 - b - dist_f
    stopifnot(r >= 0)
    r
}

star_scale2 <- function(angle) {
    stopifnot(angle >= 0, angle <= 90)
    a1 <- angle / 2
    a2 <- 180 - 90 - a1
    r <- sin(to_radians(a1)) / sin(to_radians(a2))
    stopifnot(r >= 0)
    r
}

#' @rdname star_scale
#' @export
star_angle <- function(n_vertices, scale, external = FALSE) {
    stopifnot(scale >= 0, scale <= 1)
    if (n_vertices == 2)
        return(star_angle2(scale, external))
    t <- 360 / n_vertices
    xy1 <- list(x = 1, y = 0)
    xy2 <- list(x = to_x(t, 1), y = to_y(t, 1))
    xyv <- list(x = to_x(t/2, scale), y = to_y(t/2, scale))
    xyc <- list(x = mean(c(xy1$x, xy2$x)), y = mean(c(xy1$y, xy2$y)))
    a2 <- dist(xy1, xyc)
    c <- dist(xyv, xy1)
    d <- to_degrees(2 * asin(a2 / c))
    if (!external)
        d <- external_to_internal(n_vertices, d)
    d
}

star_angle2 <- function(scale, external = FALSE) {
    d <- sqrt(1 + scale^2)
    d <- 2 * to_degrees(asin(scale / d))
    if (external)
        d <- internal_to_external(2, d)
    d
}

external_to_internal <- function(n_vertices, external) {
    n <- 2 * n_vertices # exterior plus interior vertices
    total <- (n - 2) * 180
    inverse <- 360 - external
    internal <- (total - n_vertices * inverse) / n_vertices
    internal
}

internal_to_external <- function(n_vertices, internal) {
    n <- 2 * n_vertices # exterior plus interior vertices
    total <- (n - 2) * 180
    inverse <- (total - n_vertices * internal) / n_vertices
    external <- 360 - inverse
    external
}

dist <- function(p1, p2) sqrt((p2$x - p1$x)^2 + (p2$y - p1$y)^2)

Try the gridpattern package in your browser

Any scripts or data that you put into this service are public.

gridpattern documentation built on Oct. 26, 2023, 1:07 a.m.