|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| create_gradient_circle_png <- function(size_px = NULL, diameter = NULL, palette = NULL) {
|
|
|
|
|
| cfg <- get_puzzle_config()
|
|
|
| if (is.null(size_px)) {
|
| size_px <- cfg$gradient$default_size_px
|
| }
|
|
|
| resolution <- cfg$gradient$dpi
|
|
|
|
|
| if (!is.null(diameter)) {
|
|
|
|
|
|
|
|
|
| puzzle_radius <- diameter / 2.0
|
| puzzle_offset <- puzzle_radius * 0.2
|
| canvas_size <- 2.0 * (puzzle_radius + puzzle_offset)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| coord_limit <- canvas_size / diameter
|
| } else {
|
|
|
| coord_limit <- cfg$gradient$coord_limit
|
| }
|
|
|
|
|
|
|
| coord_range <- coord_limit * cfg$gradient$range_expansion
|
| coord_limit <- coord_limit * cfg$gradient$limit_contraction
|
| x_coords <- seq(-coord_range, coord_range, length.out = resolution)
|
| y_coords <- seq(-coord_range, coord_range, length.out = resolution)
|
|
|
|
|
| gradient_matrix <- outer(x_coords, y_coords, function(x, y) {
|
|
|
| (x + y + 2*coord_range) / (4*coord_range)
|
| })
|
|
|
|
|
| palette_size <- cfg$gradient$palette_size
|
| viridis_colors <- get_puzzle_colors(palette_size, palette)
|
| color_indices <- pmax(1, pmin(palette_size, round(gradient_matrix * (palette_size - 1)) + 1))
|
| color_matrix <- array(viridis_colors[color_indices], dim = dim(gradient_matrix))
|
| gradient_raster <- as.raster(color_matrix)
|
|
|
|
|
| circle_resolution <- cfg$gradient$circle_resolution
|
| angles <- seq(0, 2*pi, length.out = circle_resolution)[-circle_resolution]
|
| circle_mask <- data.frame(
|
| x = cos(angles),
|
| y = sin(angles)
|
| )
|
|
|
|
|
| p <- ggplot() +
|
|
|
| as_reference(
|
| geom_polygon(aes(x = .data$x, y = .data$y), data = circle_mask,
|
| fill = "white", color = NA),
|
| id = "circle_mask"
|
| ) +
|
|
|
| with_mask(
|
| annotation_raster(gradient_raster,
|
| xmin = -coord_range, xmax = coord_range,
|
| ymin = -coord_range, ymax = coord_range),
|
| mask = ch_alpha("circle_mask")
|
| ) +
|
|
|
| coord_fixed(xlim = c(-coord_limit, coord_limit), ylim = c(-coord_limit, coord_limit)) +
|
| theme_void() +
|
| theme(
|
| panel.background = element_rect(fill = "white", color = NA),
|
| plot.background = element_rect(fill = "white", color = NA),
|
| plot.margin = margin(0, 0, 0, 0, "pt")
|
| )
|
|
|
| return(p)
|
| }
|
|
|
|
|
|
|
|
|
|
|
| save_gradient_background <- function(gradient_plot, background_file, size_px = NULL) {
|
|
|
|
|
| cfg <- get_puzzle_config()
|
|
|
| if (is.null(size_px)) {
|
| size_px <- cfg$gradient$default_size_px
|
| }
|
|
|
|
|
| size_inches <- size_px / cfg$gradient$dpi
|
|
|
|
|
| output_parent <- dirname(background_file)
|
| if (nzchar(output_parent) && output_parent != "." && !dir.exists(output_parent)) {
|
| dir.create(output_parent, recursive = TRUE)
|
| }
|
|
|
| ggsave(
|
| filename = background_file,
|
| plot = gradient_plot,
|
| width = size_inches, height = size_inches, units = "in", dpi = 300,
|
| bg = "white"
|
| )
|
|
|
| log_success("Background PNG saved: {.file {background_file}}")
|
| }
|
|
|