readme.md

artKIT

Overview

artKIT is an R package that includes a number of functions that are useful when creating visual/generative art. At the moment, most of the package deals with polygons/shapes, exposing functions that allows the user to do operations such as boundary interpolation, corner rounding, deformation and geometric subdivison/splitting. There are also functions for rescaling values and creating images based on functions that map pixel locations to colors.

The package is well-documented, and every function has both examples of usage and descriptions of functionality, parameters and return value.

Vectorization is used throughout the package, leading to efficient functions.

artKIT is a work in progress, and will be updated as soon as more functions are ready. If you discover any issues or bugs, please let me know.

Installation

The package can be installed by using the function install_github from devtools:

devtools::install_github("mathiasisaksen/artKIT")

Summary of content

We’ll start with the functions that deal with polygons:

The remaining functions are the following:

Usage

The documentation for a given function can be found by writing, for example, ?round_polygon_corners. Writing example("round_polygon_corners") lets you interactively run the code examples in the documentation.

Here are a couple of demonstrations of how the package can be used.

Example of polygon functions

In this example we start with a square and end up with a deformed shape cut into many pieces.

First, we create a data frame for the square:

# Data frame containing the vertices of the square
vertex.df = data.frame(x = c(1, -1, -1, 1), y = c(1, 1, -1, -1))

library(ggplot2)
# Plot showing the square and its vertices
ggplot()+
  geom_polygon(data = vertex.df, aes(x = x, y = y), fill = "red")+
  geom_point(data = vertex.df, aes(x = x, y = y), color = "black", size = 0.5)+
  coord_fixed()

The polygon is shown in red, and the vertices are shown as black points.

Next, we round the corners of the square.

library(artKIT)
rounded.df = round_polygon_corners(vertex.df, corner.radius = 0.2)
print(nrow(rounded.df))
## [1] 100

This replaces every vertex with a circular arc, and the result is a smooth shape:

ggplot()+
  geom_polygon(data = rounded.df, aes(x = x, y = y), fill = "red")+
  geom_point(data = rounded.df, aes(x = x, y = y), color = "black", size = 0.5)+
  coord_fixed()

While rounding the corners of the polygon before deformation is not required, it usually leads to better results (see example 2 under ?deform_polygon for deformation without rounding).

The rounded polygon contains 100 vertices, and these are all located along the corners. Before we deform it, we should resample points more evenly along the boundary:

# Resample 1000 points along the boundary
num.vertices = 1000
# Get num.vertices + 1 evenly placed values between 0 and 1, remove the latter since
# 0 and 1 correspond to the first vertex
interp.time = seq(0, 1, length.out = num.vertices + 1)[-(num.vertices + 1)]
# Create interpolation function and evaluate it at interp.time
resample.df = interpolate_polygon(rounded.df)(interp.time)

ggplot()+
  geom_polygon(data = resample.df, aes(x = x, y = y), fill = "red")+
  geom_point(data = resample.df, aes(x = x, y = y), color = "black", size = 0.5)+
  coord_fixed()

That looks better! interpolate_polygon returns a function that interpolates the boundary of the polygon. The function takes in values between 0 and 1, and maps these to locations on the boundary. When the input is 0, the position of the first vertex is returned. 0.5 gives the position halfway around the perimeter, and 1 closes the loop by again giving the position of the first vertex.

Next, we deform the resampled polygon. This is done using the function deform_polygon, which moves every vertex a specified distance. A positive distance moves the vertex “outwards”, while a negative distance moves it “inwards”. We define deform.function, which gives every vertex a deform distance between 0.1 and 0.3.

deform.function = function(t) 0.1 + (0.3 - 0.1)*(1 + cos(6*2*pi*t))/2
deform.distance = deform.function(interp.time)

deform.df = deform_polygon(resample.df, deform.distance)

ggplot()+
  geom_polygon(data = deform.df, aes(x = x, y = y), fill = "red")+
  geom_point(data = deform.df, aes(x = x, y = y), color = "black", size = 0.5)+
  coord_fixed()

It’s important to use a periodic function when computing the deform distance. Otherwise, there will be a gap between the first and the last vertex.

Next, we’ll cut the shape into many small pieces using the function cut_polygons. At each iteration, it cuts every piece along a randomly generated line, and the total number of polygons will, at minimum, be doubled.

cut.df = cut_polygons(deform.df, number.of.iterations = 12, seed = 123)

ggplot()+
  geom_polygon(data = cut.df, aes(x = x, y = y, group = group), 
               fill = NA, color = "black", size = 0.2)+
  coord_fixed()

Example of image_from_function

In this simple example, we use a 2D noise function from the package GRFics combined with image_from_function to create a PNG image.

We start out by setting up the GRF object:

library(GRFics)
grf.object = generate.grf.object(
  x.lower = -1.4, x.upper = 1.4, y.lower = -1, y.upper = 1, 
  resolution.x = 490, resolution.y = 350,
  range.parameter = 0.3, direction.parameter = pi/4,
  strength.parameter = 3,
  function.names = "color.value"
)

We use the rectangle (-1.4, 1.4) x (-1, 1) as our plot area, leading to an aspect ratio of 14:10. The GRF object contains one noise function named color.value.

Next, we set up the color function that will be passed to image_from_function. This function is expected to take in the positions of the pixels and return one color per pixel. The vector colors contains the colors we use in the image, and color.ramp interpolates between these colors. color.function first computes a value between 0 and 1 for each pixel, using the noise function color.value. Then, these values are plugged into color.ramp, which returns the colors in matrix format. Finally, we divide by 255 to get RGB components between 0 and 1.

colors = c("#cb0560", "#ffffff")
color.ramp = colorRamp(colors)
color.function = function(locations) {
  color.value = evaluate.grf(locations, grf.object, function.name = "color.value",
                             rescale.method = "uniform")
  rgb.matrix = color.ramp(color.value) / 255
  return(rgb.matrix)
}

In image_from_function, the size of the output image is specified with width and height. The parameter bounds determines the bounds of the rectangular grid that the pixels are placed in.

image_from_function(
  filename = "image.png", 
  color.function = color.function, 
  bounds = c(-1.4, 1.4, -1, 1),
  width = 1050, height = 750,
)



mathiasisaksen/artKIT documentation built on Dec. 21, 2021, 2:52 p.m.