diff --git a/DESCRIPTION b/DESCRIPTION index c132123..a88e2c1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: brickr Title: Tools to emulate the LEGO® System in R -Version: 0.1.0.9012 +Version: 0.1.0.9014 Authors@R: person(given = "Ryan", family = "Timpe", @@ -34,6 +34,7 @@ Collate: 'bricks-from-rayshader.R' 'bricks-from-tables.R' 'build-bricks.R' + 'build-instructions.R' 'build-mosaic.R' 'collect-bricks.R' 'colors-and-themes.R' diff --git a/NEWS.md b/NEWS.md index 511e514..1b8ff4f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,9 +7,7 @@ ## Documentation * pkgdown site -* Vignettes: - - Mosaics - - ggplot extension +* Vignettes ## Mosaics @@ -27,6 +25,7 @@ * Option to use plates rather than bricks. Combining the two involves some hacking. * Updated brick collection algorithm to allow for custom brick input. * Updated brick collection algorithm staggers bricks over layer, though still prioritizes larger bricks. +* `build_instructions` generates building instructions for 3D models, as well as mosaics. ## ggplot Extension @@ -38,11 +37,8 @@ * ggplot - continuous scale -* 3D model instructions... level by level * Vignettes - - 3D models from tables - - 3D models from coords - - 3D modesl from mosaics + rayshader + - 3D model from mosaics + rayshader - IRL * Website * Check() breaks at the size check diff --git a/R/build-instructions.R b/R/build-instructions.R new file mode 100644 index 0000000..f836c6b --- /dev/null +++ b/R/build-instructions.R @@ -0,0 +1,76 @@ +#' Create instruction manual for 2D image mosaics +#' +#' @param brickr_obj brickr mosaic or 3D model object. +#' @param num_steps Number of discrete steps in instruction manual, for mosaics only +#' @family Resources +#' @export +#' + +build_instructions <- function(brickr_obj, num_steps=6) { + in_list <- brickr_obj + image <- in_list$Img_bricks + type <- in_list$brickr_object + + #Mosaic instructions ---- + if(type == "mosaic"){ + num_steps <- min(abs(round(num_steps)), 40) + + rows_per_step <- ceiling((max(image$ymax)-0.5) / (num_steps+1)) + + create_steps <- function(a, n_steps) { + if(a < n_steps){ + image %>% + dplyr::group_by(brick_name) %>% + dplyr::filter(min(ymin) <= a*rows_per_step+(min(image$ymin)+0.5)) %>% + dplyr::ungroup() %>% + dplyr::mutate(Step = paste("Step", stringr::str_pad(a, 2, pad = "0"))) + } else { + image %>% + dplyr::mutate(Step = paste("Step", stringr::str_pad(a, 2, pad = "0"))) + } + } + + steps_for_plot <- 1:num_steps %>% + purrr::map_df(create_steps, num_steps) %>% + dplyr::mutate(alpha = 1) + + } #end mosaics + + else if(type == "3dmodel"){ + num_steps <- length(unique(image$Level)) + + create_steps <- function(a, n_steps) { + image %>% + dplyr::filter(between(Level, a-1, a)) %>% + dplyr::mutate(alpha = ifelse(Level == a, 1, 0.5)) %>% + dplyr::mutate(Step = paste("Step", stringr::str_pad(a, 2, pad = "0"))) + + } + + steps_for_plot <- 1:num_steps %>% + purrr::map_df(create_steps, num_steps) + + } + + #Plot ---- + coord_ratio <- 1 + + steps_for_plot %>% + ggplot2::ggplot() + + ggplot2::geom_rect(ggplot2::aes(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, + fill = Lego_color, alpha = alpha), color = "#333333") + + ggplot2::scale_fill_identity() + + ggplot2::scale_alpha_identity() + + ggplot2::coord_fixed(ratio = coord_ratio, expand = TRUE) + + ggplot2::facet_wrap(~Step) + + ggplot2::theme_minimal() + + ggplot2::theme( panel.background = ggplot2::element_rect(fill = "#7EC0EE"), + strip.background = ggplot2::element_rect(fill = "#F7F18D"), + strip.text = ggplot2::element_text(color = "#333333", face = "bold"), + axis.line = ggplot2::element_blank(), + axis.title.x = ggplot2::element_blank(), + axis.text.x = ggplot2::element_blank(), + axis.title.y = ggplot2::element_blank(), + axis.text.y = ggplot2::element_blank(), + legend.position = "none") +} diff --git a/R/build-mosaic.R b/R/build-mosaic.R index 0883b3d..f7499fa 100644 --- a/R/build-mosaic.R +++ b/R/build-mosaic.R @@ -1,21 +1,19 @@ #' Display 2D LEGO mosaic as a plot image #' -#' @param image_list List output from collect_bricks() or image_to_bricks(). Contains an element \code{Img_lego}. +#' @param brick_obj List output from image_to_bricks(). Contains an element \code{Img_lego}. #' @param title Optional title to include above plotted mosaic. #' @family Mosaics #' @export #' -build_mosaic <- function(image_list, title=NULL){ - in_list <- image_list +build_mosaic <- function(brick_obj, title=NULL){ + in_list <- brick_obj image <- in_list$Img_bricks type <- in_list$mosaic_type coord_x <- c(min(image$xmin)+0.5, max(image$xmax)-0.5) coord_y <- c(min(image$ymin)+0.5, max(image$ymax)-0.5) - - if(type == "stacked") stop("Stacked mosaics have been removed from brickr. Only flat / 'knobs-up' mosaics are supported.") - + img <- ggplot2::ggplot(in_list$Img_lego, ggplot2::aes(x=x, y=y)) + geom_brick_rect(ggplot2::aes(fill = Lego_color), color = "#333333")+ ggplot2::scale_fill_identity() + @@ -28,56 +26,3 @@ build_mosaic <- function(image_list, title=NULL){ return(img) } -#' Create instruction manual for 2D image mosaics -#' -#' @param image_list Mosaic object from image_to_mosaic(). -#' @param num_steps Number of discrete steps in instruction manual -#' @family Mosaics -#' @export -#' - -build_instructions <- function(image_list, num_steps=6) { - in_list <- image_list - image <- in_list$Img_bricks - type <- in_list$mosaic_type - - num_steps <- min(abs(round(num_steps)), 40) - - rows_per_step <- ceiling((max(image$ymax)-0.5) / (num_steps+1)) - - create_steps <- function(a, n_steps) { - if(a < n_steps){ - image %>% - dplyr::group_by(brick_name) %>% - dplyr::filter(min(ymin) <= a*rows_per_step+(min(image$ymin)+0.5)) %>% - dplyr::ungroup() %>% - dplyr::mutate(Step = paste("Step", (if(a<10){paste0('0', a)}else{a}))) - } else { - image %>% - dplyr::mutate(Step = paste("Step", (if(a<10){paste0('0', a)}else{a}))) - } - - } - - #Ratio of the "pixels" is different for flat or stacked bricks - coord_ratio <- 1 - - 1:num_steps %>% - purrr::map(create_steps, num_steps) %>% - dplyr::bind_rows() %>% - ggplot2::ggplot() + - ggplot2::geom_rect(ggplot2::aes(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, - fill = Lego_color), color = "#333333") + - ggplot2::scale_fill_identity() + - ggplot2::coord_fixed(ratio = coord_ratio, expand = FALSE) + - ggplot2::facet_wrap(~Step) + - ggplot2::theme_minimal() + - ggplot2::theme( panel.background = ggplot2::element_rect(fill = "#7EC0EE"), - strip.background = ggplot2::element_rect(fill = "#F7F18D"), - strip.text = ggplot2::element_text(color = "#333333", face = "bold"), - axis.line = ggplot2::element_blank(), - axis.title.x = ggplot2::element_blank(), - axis.text.x = ggplot2::element_blank(), - axis.title.y = ggplot2::element_blank(), - axis.text.y = ggplot2::element_blank()) -} diff --git a/R/collect-bricks.R b/R/collect-bricks.R index b70c2de..826de1b 100644 --- a/R/collect-bricks.R +++ b/R/collect-bricks.R @@ -111,7 +111,6 @@ collect_bricks <- function(image_list, use_bricks = NULL){ in_list[["Img_bricks"]] <- img2 in_list[["ID_bricks"]] <- bricks_df - in_list[["mosaic_type"]] <- "flat" in_list[["pieces"]] <- pcs return(in_list) diff --git a/R/piece-count.R b/R/piece-count.R index cc4ad1d..9398588 100644 --- a/R/piece-count.R +++ b/R/piece-count.R @@ -1,12 +1,12 @@ #' Generate required bricks as a data frame. #' -#' @param image_list Mosaic output from image_to_mosaic(). +#' @param brick_obj brickr mosaic or 3D model object. #' @return Data frame of piece counts by LEGO color name and size. #' @family Resources #' @export -build_pieces_table <- function(image_list){ - pcs <- image_list$pieces +build_pieces_table <- function(brick_obj){ + pcs <- brick_obj$pieces pcs %>% dplyr::select(-Lego_color) %>% @@ -14,26 +14,25 @@ build_pieces_table <- function(image_list){ dplyr::rename(`LEGO Brick Color` = Lego_name) } -#' Graphically display required bricks. +#' Display bricks required to build model or mosaic. #' -#' @param image_list Mosaic output from image_to_mosaic(). +#' @param brick_obj brickr mosaic or 3D model object. #' @return Plot object of required bricks by color and size. #' @family Resources #' @export #' -build_pieces <- function(image_list){ - in_list <- image_list +build_pieces <- function(brick_obj){ + in_list <- brick_obj pcs <- in_list$pieces - - pcs_coords <- dplyr::tibble( - Brick_size = c("1 x 1", "2 x 1", "3 x 1", "4 x 1", "2 x 2", "4 x 2"), - xmin = c(0, 0, 0, 0, 6, 6), - xmax = c(1, 2, 3, 4, 8, 8), - ymin = c(0, 2, 4, 6, 0, 3), - ymax = c(1, 3, 5, 7, 2, 7) - ) + pcs_coords <- dplyr::tibble( + Brick_size = c("1 x 1", "2 x 1", "3 x 1", "4 x 1", "2 x 2", "4 x 2"), + xmin = c(0, 0, 0, 0, 6, 6), + xmax = c(1, 2, 3, 4, 8, 8), + ymin = c(0, 2, 4, 6, 0, 3), + ymax = c(1, 3, 5, 7, 2, 7) + ) #This function creates nodes in each brick for stud placement pcs_coords <- pcs_coords %>% @@ -45,33 +44,28 @@ build_pieces <- function(image_list){ pcs2 <- pcs %>% dplyr::arrange(Lego_color) %>% dplyr::mutate(Lego_name = factor(Lego_name, - levels = c("Black", - unique(Lego_name)[!(unique(Lego_name) %in% c("Black", "White"))], - "White"))) %>% + levels = c("Black", + unique(Lego_name)[!(unique(Lego_name) %in% c("Black", "White"))], + "White"))) %>% dplyr::left_join(pcs_coords, by = "Brick_size") - coord_xlim <- c(-0.5, 10) - facet_cols <- 5 - + coord_xlim <- c(-0.5, 10) + facet_cols <- 5 + pcs2 %>% ggplot2::ggplot() + ggplot2::geom_rect(ggplot2::aes(xmin=xmin, xmax=xmax, ymin=-ymin, ymax=-ymax, - fill = Lego_color), color = "#333333")+ + fill = Lego_color), color = "#333333")+ ggplot2::scale_fill_identity() + ggplot2::geom_point(data = pcs2 %>% tidyr::unnest(studs), ggplot2::aes(x=x, y=-y), color = "#cccccc", alpha = 0.25, - shape = 1, size = 2) + + shape = 1, size = 2) + ggplot2::geom_text( - ggplot2::aes(x = xmax + 0.25, y = -(ymin+ymax)/2, label = paste0("x", n)), - hjust = 0, vjust = 0.5, size = 3.5) + + ggplot2::aes(x = xmax + 0.25, y = -(ymin+ymax)/2, label = paste0("x", n)), + hjust = 0, vjust = 0.5, size = 3.5) + ggplot2::coord_fixed(xlim = coord_xlim) + - ggplot2::labs(title = (if(in_list$mosaic_type == "stacked"){ - "Suggested LEGO Bricks" - }else{"Suggested LEGO Plates"}), - caption = (if(in_list$mosaic_type == "stacked"){ - "Mosaic is 2-bricks deep. Can substitute 2-stud bricks for 1-stud alternatives for a thinner mosaic."}else{""}) - ) + + ggplot2::labs(title = "Suggested LEGO Bricks") + ggplot2::facet_wrap(~Lego_name, ncol=facet_cols) + ggplot2::theme_minimal() + ggplot2::theme( panel.background = ggplot2::element_rect(fill = "#7EC0EE"), diff --git a/README.Rmd b/README.Rmd index 3661c41..377dfd8 100644 --- a/README.Rmd +++ b/README.Rmd @@ -174,10 +174,7 @@ sphere_coords %>% bricks_from_coords() %>% build_bricks(phi = 30, theta = 30) -rayshader::render_snapshot() -``` -```{r, echo=FALSE} - rgl::rgl.clear() +rayshader::render_snapshot(clear = TRUE) ``` ### Examples diff --git a/README.md b/README.md index ec3bad0..ae71442 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ brick %>% bricks_from_table() %>% build_bricks(brick_res = "uhd") -rayshader::render_snapshot() +rayshader::render_snapshot( clear = TRUE) ```  @@ -185,7 +185,7 @@ my_first_model %>% bricks_from_table(brick_colors) %>% build_bricks(theta = 210, brick_res = "hd") -rayshader::render_snapshot() +rayshader::render_snapshot(clear = TRUE) ```  @@ -218,7 +218,7 @@ sphere_coords %>% bricks_from_coords() %>% build_bricks(phi = 30, theta = 30) -rayshader::render_snapshot() +rayshader::render_snapshot(clear = TRUE) ```  diff --git a/README_files/figure-gfm/geom_brick2-1.png b/README_files/figure-gfm/geom_brick2-1.png index 6fa750b..71c8df2 100644 Binary files a/README_files/figure-gfm/geom_brick2-1.png and b/README_files/figure-gfm/geom_brick2-1.png differ diff --git a/README_files/figure-gfm/m1_instructions-1.png b/README_files/figure-gfm/m1_instructions-1.png index aa82670..28ec7ff 100644 Binary files a/README_files/figure-gfm/m1_instructions-1.png and b/README_files/figure-gfm/m1_instructions-1.png differ diff --git a/README_files/figure-gfm/m1_pieces-1.png b/README_files/figure-gfm/m1_pieces-1.png index 9f10081..cb5fd2f 100644 Binary files a/README_files/figure-gfm/m1_pieces-1.png and b/README_files/figure-gfm/m1_pieces-1.png differ diff --git a/_pkgdown.yml b/_pkgdown.yml index 52a00a2..0cb5cda 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -26,4 +26,4 @@ reference: - build_colors - build_instructions - starts_with("build_pieces") - - build_themes \ No newline at end of file + - build_themes diff --git a/docs/LICENSE-text.html b/docs/LICENSE-text.html index 7172b10..3ad2e03 100644 --- a/docs/LICENSE-text.html +++ b/docs/LICENSE-text.html @@ -70,7 +70,7 @@ @@ -95,6 +95,15 @@


geom_brick_col() draws data columns as bricks.







vignettes/models-from-other.Rmd
+ models-from-other.RmdThe bricks_from_* series of functions creates 3D models of LEGO bricks from a variety of input formats. These models are rendered using Tyler Morgan-Wall’s rayshader package. This package must be installed.
Begin with a brickr mosaic from an image. Rather than graphically rendering the mosaic using build_mosaic(), use bricks_from_mosaic(). This function takes two other inputs:
mosaic_height is the number of bricks stacked at the mosaic’s highest point. The default is 6.highest_el specifies if ‘light’ or ‘dark’ color bricks should be the tallest in the model. The default is ‘light’.mosaic <- png::readPNG("../Images/mf_unicorn.PNG") %>%
+ image_to_mosaic()
+
+mosaic %>% build_mosaic()
+mosaic %>%
+ bricks_from_mosaic(highest_el = "dark") %>%
+ build_bricks(phi = 60, theta = 15)
+
+rayshader::render_snapshot(clear = TRUE)
rayshader by Tyler Morgan-Wall is an open source package for producing 2D and 3D data visualizations in R. rayshader uses elevation data in a base R matrix and a combination of raytracing, spherical texture mapping, overlays, and ambient occlusion to generate beautiful topographic 2D and 3D maps. (Note: text lifted straight from rayshader.com.)
+3D models in brickr are rendered using the functions in rayshader. Using bricks_from_rayshader(), you can convert rayshader map output into a brickr model. This function takes three inputs:
hillshade is topographic image matrix with an RGB channel (much like the mosaics).heightmap is a two-dimensional matrix specifiying the height of the image at each location.max_height is the number of bricks stacked at the mosaic’s highest point. The default is 12.img_size is the number of bricks on each side of the model. The default is 48.library(rayshader)
+
+#Example from rayshader.com
+
+#Here, I load a map with the raster package.
+loadzip = tempfile()
+download.file("https://tylermw.com/data/dem_01.tif.zip", loadzip)
+localtif = raster::raster(unzip(loadzip, "dem_01.tif"))
+unlink(loadzip)
+
+#And convert it to a matrix:
+elmat = matrix(raster::extract(localtif, raster::extent(localtif), buffer = 1000),
+ nrow = ncol(localtif), ncol = nrow(localtif))
+
+rayshader_object <- elmat %>%
+ sphere_shade(texture = "desert") %>%
+ add_water(detect_water(elmat), color = "desert") %>%
+ add_shadow(ray_shade(elmat, zscale = 3, maxsearch = 300), 0.5)
+
+#Plot with rayshader
+rayshader_object %>%
+ plot_3d(elmat, zscale = 10, fov = 0, theta = 135, zoom = 0.75, phi = 45, windowsize = c(1000, 800))
+
+rayshader::render_snapshot(clear = TRUE)
+#Plot as bricks
+rayshader_object %>%
+ bricks_from_rayshader(elmat) %>%
+ build_bricks(theta = 135, zoom = 0.75, phi = 45)
+
+rayshader::render_snapshot(clear = TRUE)
vignettes/models-from-program.Rmd
+ models-from-program.RmdThe bricks_from_* series of functions creates 3D models of LEGO bricks from a variety of input formats. These models are rendered using Tyler Morgan-Wall’s rayshader package. This package must be installed.
Use bricks_from_coords() to programmatically build 3D LEGO models rather than manually drawing them in a spreadsheet or table. Prove the function with a data frame with x, y, and z coordinates, along with an official LEGO color name for each point.
Below, we create a 8x8x8 cube by expanding a data frame with the array 1:8 as the x-, y-, and z-coordinates. We then assign each row of that data frame one of three colors: Bright blue, Bright yellow, or Bright red.
+use_colors <- c("Bright blue", "Bright yellow", "Bright red")
+
+cube <- expand.grid(
+ x = 1:8,
+ y = 1:8,
+ z = 1:8
+)
+
+cube$Color <- sample(use_colors, nrow(cube), replace = TRUE, prob = c(5, 3, 1))
+
+cube %>%
+ bricks_from_coords() %>%
+ build_bricks(brick_res = "hd", phi = 30, theta = 30)
+
+rayshader::render_snapshot(clear = TRUE)
Using the same logic, we can build a sphere with a specified radius, and then apply rules to color each brick based on its coordinates.
+radius <- 4
+sphere_coords <- expand.grid(
+ x = 1:round((radius*2.5)),
+ y = 1:round((radius*2.5)),
+ z = 1:round((radius/(6/5)*2.5)) #A brick is 6/5 taller than it is wide/deep
+) %>%
+ dplyr::mutate(
+ #Distance of each coordinate from center
+ dist = (((x-mean(x))^2 + (y-mean(y))^2 + (z-mean(z))^2)^(1/2)),
+ Color = dplyr::case_when(
+ #Yellow stripes on the surface with a 2to4 thickness
+ dplyr::between(dist, (radius-1), radius) & (x+y+z) %% 6 %in% 0:1 ~ "Bright yellow",
+ #Otherwise, sphere is blue
+ dist <= radius ~ "Bright blue"
+ ))
+
+sphere_coords %>%
+ bricks_from_coords() %>%
+ build_bricks(brick_res = "hd", phi = 30, theta = 30)
+
+rayshader::render_snapshot(clear = TRUE)
Rather than directly writing a data frame for a model, you can write a function that returns a data frame with x, y, z, and Color coordinates given initial starting parameters.
+Below, the function brick_house() creates a LEGO house with randomized colors. The x- and y-coordinates and the size of the house are inputs to the functions.
brick_house <- function(x_coord = 0, y_coord = 0, width=6, length=5, height=6){
+ roof_colors <- c("Dark orange", "Dark brown", "Medium nougat", "Medium stone grey")
+ roof_col <- sample(roof_colors, 1)
+
+ house_colors <- c("Bright blue", "Bright red", "Dark red", "Dark azur", "Nougat", "Bright reddish violet")
+ house_col <- sample(house_colors, 1)
+
+ house_coords <- expand.grid(
+ x = 1:width, y = 1:length, z = (1:height)+1
+ ) %>%
+ dplyr::mutate(
+ roof = (z > round((1/2)*height)),
+ Color = dplyr::case_when(
+ #Roof
+ roof & (abs(y - floor(length/2) -1) <= (height-z)) ~ roof_col,
+ roof ~ NA_character_,
+ #Door and windows
+ x == round(width/2) & z == 1 ~ NA_character_,
+ dplyr::between(x, 2, width-1) & x %% 2 == 0 & y > 1 & z == 2 ~ NA_character_,
+ dplyr::between(y, 2, length-1) & y %% 2 == 0 & z == 2 ~ NA_character_,
+ x %in% c(1, width) | y %in% c(1, length) ~ house_col),
+ x = x+x_coord,
+ y = y+y_coord
+ )
+ return(house_coords)
+}
+
+#Build one house
+brick_house() %>% bricks_from_coords() %>%
+ build_bricks(theta = 225)
+rayshader::render_snapshot(clear = TRUE)
Next, we write one more function, brick_street() to build a road and grass foundation. The, for an arbitrary number of houses and neighborhood size, use purrr::pmap_df to generate many houses and place them along the road.
brick_street <- function(width = 100, length = 40){
+ expand.grid(x=1:width, y=1:length, z=1) %>%
+ dplyr::mutate(
+ Color = dplyr::case_when(
+ y == round(length/2) & x %% 4 %in% 1:4 ~ "Bright yellow",
+ dplyr::between(y, length/2 -5, length/2 +5) ~ "Dark stone grey",
+ TRUE ~ "Dark green"
+ ))
+}
+
+#Build a village, houses on 2 sides of a street
+n_houses = 14
+sz = c(100, 40)
+
+list(x_coord = c(sample(seq(10, sz[1]-10, by = 10), n_houses/2),
+ sample(seq(10, sz[1]-10, by = 10), n_houses/2)),
+ y_coord = c(rep(sz[2]/2-15, n_houses/2), rep(sz[2]/2+10, n_houses/2)),
+ width = sample(4:10, n_houses, replace = TRUE),
+ length = sample(4:8, n_houses, replace = TRUE),
+ height = sample(5:8, n_houses, replace = TRUE)
+ ) %>%
+ purrr::pmap_df(brick_house) %>%
+ dplyr::bind_rows(brick_street(sz[1], sz[2])) %>%
+ bricks_from_coords() %>%
+ build_bricks()
+
+rayshader::render_camera(theta = 60, phi = 20, zoom = 0.75)
+rayshader::render_snapshot(clear = TRUE)
The bricks_from_* series of functions creates 3D models of LEGO bricks from a variety of input formats. These models are rendered using Tyler Morgan-Wall’s rayshader package. This package must be installed.
bricks_from_table() converts a matrix-shaped table of integers into LEGO bricks, where most columns are x-coordinates, rows are y-coordinates, and a special Level column denotes the elevation of the row. For simple models, this table can be made manually using data.frame() or tibble::tribble().
For more advanced models, it’s recommended you use MS Excel or a .csv file. bricks_from_excel() is a wrapper function to more easily build models designed using a Microsoft Excel template. Please see this repo: brickr toybox.
Pass the output of any bricks_from_*() function to build_bricks() to render it as a 3D model.
Create a single 2x4 brick with a 2x4 data frame, with an additional column to specify the ‘Level’. These can be letters or numbers.
+#This is a 2 (columns) x 4 (rows) brick
+(brick <- data.frame(
+ Level="A",
+ X1 = rep(3,4), #The number 3 is the brickrID for 'bright red'
+ X2 = rep(3,4)
+))
+#> Level X1 X2
+#> 1 A 3 3
+#> 2 A 3 3
+#> 3 A 3 3
+#> 4 A 3 3
+
+brick %>%
+ bricks_from_table() %>%
+ build_bricks(brick_res = "hd") #Bricks available in standard def, high def, and ultra hd.
+
+rayshader::render_snapshot( clear = TRUE)
Stack many bricks by changing the ‘Level’ value in the data frame. The script below uses purrr::map_df() to avoid copying and pasting. Changing the numeric values inside the data frame for each level creates different colors.
1:10 %>%
+ purrr::map_df(~dplyr::mutate(brick,
+ Level = LETTERS[.x],
+ X1 = .x,
+ X2 = .x)) %>%
+ bricks_from_table() %>%
+ build_bricks(brick_res = "hd")
+
+rayshader::render_snapshot( clear = TRUE)
The most direct way to create a 3D model is to manually create a data frame. Below, we create a data frame using tibble::tribble() so we can more easily see the structure as it’s written.
The data frame has 3 numbers as input (values of 0 are void spaces in the model). Rather than use the default brickr colors for the values of 1, 2, and 3, we define another data frame ‘brick_colors’
+tree_or_mushroom <- tibble::tribble(
+ ~Level, ~X1, ~X2, ~X3, ~X4, ~X5, ~X6,
+ "A", 1, 1, 1, 1, 1, 1,
+ "A", 1, 1, 1, 1, 1, 1,
+ "A", 1, 1, 1, 1, 1, 1,
+ "A", 1, 1, 1, 1, 1, 1,
+ "B", 0, 0, 0, 0, 0, 0,
+ "B", 0, 0, 2, 2, 0, 0,
+ "B", 0, 0, 2, 2, 0, 0,
+ "B", 0, 0, 0, 0, 0, 0,
+ "C", 0, 0, 0, 0, 0, 0,
+ "C", 0, 0, 2, 2, 0, 0,
+ "C", 0, 0, 2, 2, 0, 0,
+ "C", 0, 0, 0, 0, 0, 0,
+ "D", 0, 3, 3, 3, 3, 0,
+ "D", 0, 3, 3, 3, 3, 0,
+ "D", 0, 3, 3, 3, 3, 0,
+ "D", 0, 3, 3, 3, 3, 0,
+ "E", 0, 0, 3, 3, 0, 0,
+ "E", 0, 3, 3, 3, 3, 0,
+ "E", 0, 3, 3, 3, 3, 0,
+ "E", 0, 0, 3, 3, 0, 0,
+ "F", 0, 0, 0, 0, 0, 0,
+ "F", 0, 0, 3, 3, 0, 0,
+ "F", 0, 0, 3, 3, 0, 0,
+ "F", 0, 0, 0, 0, 0, 0,
+ "G", 0, 0, 0, 0, 0, 0,
+ "G", 0, 0, 3, 0, 0, 0,
+ "G", 0, 0, 0, 3, 0, 0,
+ "G", 0, 0, 0, 0, 0, 0
+)
+
+brick_colors <- tibble::tribble(
+ ~`.value`, ~Color,
+ 1, "Bright green",
+ 2, "Dark orange",
+ 3, "Dark green"
+)
+
+tree_or_mushroom %>%
+ bricks_from_table(brick_colors) %>%
+ build_bricks(theta = 210, phi = 20, brick_res = "hd")
+
+rayshader::render_snapshot(clear = TRUE)
That’s clearly a tree, right? Why is the data frame called ‘tree_or_mushroom’?
+Use the input ‘brick_type=“plate”’ to render the 3D model using LEGO plates rather than bricks, which are 1/3 as tall.
+brick_colors <- tibble::tribble(
+ ~`.value`, ~Color,
+ 1, "Dark green",
+ 2, "Light nougat",
+ 3, "Bright red"
+)
+
+tree_or_mushroom %>%
+ bricks_from_table(brick_colors) %>%
+ build_bricks(theta = 210, phi = 10, brick_res = "hd", brick_type="plate")
+
+rayshader::render_snapshot(clear = TRUE)
When designing larger models, it is much easier to use a spreadsheet program to lay out the bricks for each level.
+See the brickr toybox GitHub repo for some examples and templates.
+brickr also includes tools help users create the Mosaics and 3D model output using real LEGO® elements.
+The goal of {brickr} is to provide a series of tools to integrate the LEGO® system with R by:
+brickr is developed using publicly available information about LEGO® products and is not officially affiliated with The LEGO Group



Breaking: Pretty much EVERY function. Seriously, check out the README and start fresh.
Breaking: Data “lego_colors.rda” has been updated with more accurate RGB values and new brickrID numbers. This will impact previously created mosaics and 3D models.
build_instructions generates building instructions for 3D models, as well as mosaics.ggplot - continuous scale
Other Resources: build_pieces_table,
+
Other Resources: build_instructions,
+ build_pieces_table,
build_pieces, build_themes
R/build-mosaic.R
+ Source: R/build-instructions.R
build_instructions.Rdbuild_instructions(image_list, num_steps = 6)+
build_instructions(brickr_obj, num_steps = 6)
| image_list | -Mosaic object from image_to_mosaic(). |
+ brickr_obj | +brickr mosaic or 3D model object. |
|---|---|---|---|
| num_steps | -Number of discrete steps in instruction manual |
+ Number of discrete steps in instruction manual, for mosaics only |
Other Mosaics: build_mosaic,
- image_to_mosaic
Other Resources: build_colors,
+ build_pieces_table,
+ build_pieces, build_themes
build_mosaic(image_list, title = NULL)+
build_mosaic(brick_obj, title = NULL)
| image_list | -List output from collect_bricks() or image_to_bricks(). Contains an element |
+ brick_obj | +List output from image_to_bricks(). Contains an element |
||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| title | @@ -154,8 +163,7 @@
| image_list | -Mosaic output from image_to_mosaic(). |
+ brick_obj | +brickr mosaic or 3D model object. |
|---|
Other Resources: build_colors,
+ build_instructions,
build_pieces_table,
build_themes
build_pieces_table(image_list)+
build_pieces_table(brick_obj)
| image_list | -Mosaic output from image_to_mosaic(). |
+ brick_obj | +brickr mosaic or 3D model object. |
|---|
Other Resources: build_colors,
+ build_instructions,
build_pieces, build_themes
Other Resources: build_colors,
+ build_instructions,
build_pieces_table,
build_pieces
color_table is sup
Other Mosaics: build_instructions,
- build_mosaic
Other Mosaics: build_mosaic
Graphically display required bricks.
Display bricks required to build model or mosaic.