From cfeddd6bde7b7edac8bbb35d528599c5016479be Mon Sep 17 00:00:00 2001 From: ryantimpe Date: Sun, 8 Mar 2020 11:45:48 -0400 Subject: [PATCH] Cheese slopes! Woot woot woot. --- DESCRIPTION | 2 +- R/bricks-from-tables.R | 5 ++- R/build-bricks-rgl.R | 83 ++++++++++++++++++++++++++++++++++++--- man/bricks_from_coords.Rd | 3 +- man/bricks_from_excel.Rd | 3 ++ man/bricks_from_table.Rd | 5 ++- 6 files changed, 92 insertions(+), 9 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 932de35..73eeeee 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: brickr Title: Tools to emulate the LEGO® System in R -Version: 0.2.9.9003 +Version: 0.2.9.9103 Authors@R: person(given = "Ryan", family = "Timpe", diff --git a/R/bricks-from-tables.R b/R/bricks-from-tables.R index bbcdb8e..b392e5c 100644 --- a/R/bricks-from-tables.R +++ b/R/bricks-from-tables.R @@ -2,6 +2,7 @@ #' #' @param matrix_table A data frame of a 3D brick model design. Left-most column is level/height/z dimension, with rows as Y axis and columns as X axis. See example. Use \code{tribble} for ease. #' @param color_guide A data frame linking numeric \code{.value} in \code{matrix_table} to official LEGO color names. Defaults to data frame 'lego_colors'. +#' @param piece_matrix A data frame in same shape as \code{matrix_table} with piece shape IDs. #' @param .re_level Logical to reassign the Level/z dimension to layers in alphanumeric order. Set to FALSE to explicitly provide levels. #' @param increment_level Default '0'. Use in animations. Shift Level/z dimension by an integer. #' @param max_level Default 'Inf'. Use in animations. Any Level/z values above this value will be cut off. @@ -149,6 +150,7 @@ bricks_from_table <- function(matrix_table, color_guide = brickr::lego_colors, #' Convert an Excel {brickr} template into a brickr 3D object #' @param excel_table Sheet imported from a brickr Excel template to build model. Contains stud placement and colors. +#' @param piece_table Sheet identical in shape to \code{excel_table} with piece shape IDs. #' @param repeat_levels How many times to repeat a level. Can save time in model planning. Default is 1. #' @inheritParams bricks_from_table #' @return A list with elements \code{Img_lego} to pass to \code{collect_bricks()}. @@ -230,7 +232,8 @@ bricks_from_excel <- function(excel_table, #' Convert a data frame with x, y, z & Color columns into a brickr 3D object #' -#' @param coord_table A data frame of a 3D brick model design. Contains x, y, and z (vertical height) dimensions, as well as Color from official LEGO color names. See \code{build_colors()}. +#' @param coord_table A data frame of a 3D brick model design. Contains x, y, and z (vertical height) dimensions, as well as Color from official LEGO color names. +#' See \code{build_colors()}. Optional column piece_type for shapes other than rectangular bricks. #' @param increment_level Default '0'. Use in animations. Shift Level/z dimension by an integer. #' @param max_level Default 'Inf'. Use in animations. Any Level/z values above this value will be cut off. #' @param increment_x Default '0'. Use in animations. Shift x dimension by an integer. diff --git a/R/build-bricks-rgl.R b/R/build-bricks-rgl.R index 2c821d7..a30c259 100644 --- a/R/build-bricks-rgl.R +++ b/R/build-bricks-rgl.R @@ -52,7 +52,6 @@ build_bricks <- function(brick_list, # For use inside brick drawing functions below nudge = 0.01 #Space between bricks scale = 1 #Reduce to unit size - # trans_alpha = 0.5 #Alpha of transparent bricks height_scale = 9.6/7.8 color_outline = "black" @@ -65,12 +64,14 @@ build_bricks <- function(brick_list, outline_bricks = outline_bricks - suppress_knobs = TRUE + suppress_knobs = TRUE #this won't draw 'hidden' knobs + + pieces_knobbed = c("B", "P") #For now, use the current collect_bricks output. #This was designed for rayshader, and I don't want to drop rayshader just yet. - #Bricks without knobs ---- + #Bricks & pieces without knobs ---- rgl_bricks_base <- list( # x & y are the CENTERS of bricks. rgl scales shapes from center @@ -82,12 +83,14 @@ build_bricks <- function(brick_list, lum = img_bricks$lum, #Grab brick size from brick type id width = as.numeric(substr(img_bricks$brick_type, 2, 2)), - length = as.numeric(substr(img_bricks$brick_type, 4, 4)) + length = as.numeric(substr(img_bricks$brick_type, 4, 4)), + piece = img_bricks$piece_type ) %>% purrr::transpose() rgl_bricks_base_list <- rgl_bricks_base %>% purrr::map(function(this_brick){ + if(!(this_brick$piece %in% pieces_knobbed)){return(NULL)} #Solid brick ---- brk_fill <- rgl::cube3d(col = this_brick$color, @@ -124,6 +127,71 @@ build_bricks <- function(brick_list, return(out_list) }) %>% + purrr::discard(is.null) %>% + purrr::transpose() + + rgl_bricks_wedge_list <- rgl_bricks_base %>% + purrr::map(function(this_brick){ + if(!(this_brick$piece %in% paste0("w", 1:4))){return(NULL)} + + #Solid brick ---- + brk_fill <- rgl::cube3d(col = this_brick$color, + alpha = if(this_brick$trans){trans_alpha}else{1}) + + #Turn it into a wedge + w_lhs <- switch(this_brick$piece, + w1 = c(7, 8), + w2 = c(6, 8), + w3 = c(5, 6), + w4 = c(5, 7)) + + w_rhs <- switch(this_brick$piece, + w1 = c(3, 4), + w2 = c(2, 4), + w3 = c(1, 2), + w4 = c(1, 3)) + + w_ratio = 1.2/4 + + brk_fill$vb[, w_lhs] <- brk_fill$vb[, w_rhs] * (1-w_ratio) + brk_fill$vb[, w_lhs] * w_ratio + + brk_fill$vb[4,] <- brk_fill$vb[4,]/scale*2 + nudge + + brk_fill2 <- brk_fill %>% + rgl::scale3d(this_brick$width, this_brick$length, height_scale * 2/3) %>% #Increase height + rgl::translate3d(this_brick$x, this_brick$y, + this_brick$z * height_scale - height_scale*(1-2/3)/2) + + if(outline_bricks){ + # Brick Outline ---- + brk_out <- rgl::cube3d(col = if(this_brick$trans){colorspace::lighten(this_brick$color)} + else{color_outline}) + + #Turn it into a wedge + brk_out$vb[, w_lhs] <- brk_out$vb[, w_rhs] * (1-w_ratio) + brk_out$vb[, w_lhs] * w_ratio + + brk_out$vb[4,] <- brk_out$vb[4,]/scale*2 + nudge + + brk_out$material$lwd <- 1 + brk_out$material$front <- 'line' + brk_out$material$back <- 'line' + + brk_out2 <- brk_out %>% + rgl::scale3d(this_brick$width, this_brick$length, height_scale * 2/3) %>% #Increase height + rgl::translate3d(this_brick$x, this_brick$y, + this_brick$z * height_scale - height_scale*(1-2/3)/2) + + out_list <- list(brk_fill2, brk_out2) + } else { + brk_out2 <- NULL + out_list <- list(brk_fill2, brk_out2) + } + + #Save ---- + return(out_list) + + }) %>% + purrr::discard(is.null) %>% purrr::transpose() #Bricks knobs ---- @@ -148,12 +216,14 @@ build_bricks <- function(brick_list, z = img_lego$Level, color = img_lego$Lego_color, trans = img_lego$Trans_lego, - lum = img_lego$lum + lum = img_lego$lum, + piece = img_lego$piece_type ) %>% purrr::transpose() rgl_bricks_knobs_list <- rgl_bricks_knobs %>% purrr::map(function(this_brick){ + if(!(this_brick$piece %in% pieces_knobbed)){return(NULL)} # Brick knob ---- brk_knob <- rgl::cylinder3d(matrix(c(rep(1, 3), rep(1, 3))/2, ncol=2, byrow = TRUE), @@ -244,11 +314,14 @@ build_bricks <- function(brick_list, return(out_list) }) %>% + purrr::discard(is.null) %>% purrr::transpose() #Draw shapelist <- c(rgl_bricks_base_list[[1]] , rgl_bricks_base_list[[2]] + , rgl_bricks_wedge_list[[1]] + , rgl_bricks_wedge_list[[2]] , purrr::flatten(rgl_bricks_knobs_list) ) diff --git a/man/bricks_from_coords.Rd b/man/bricks_from_coords.Rd index ec18397..55735aa 100644 --- a/man/bricks_from_coords.Rd +++ b/man/bricks_from_coords.Rd @@ -17,7 +17,8 @@ bricks_from_coords( ) } \arguments{ -\item{coord_table}{A data frame of a 3D brick model design. Contains x, y, and z (vertical height) dimensions, as well as Color from official LEGO color names. See \code{build_colors()}.} +\item{coord_table}{A data frame of a 3D brick model design. Contains x, y, and z (vertical height) dimensions, as well as Color from official LEGO color names. +See \code{build_colors()}. Optional column piece_type for shapes other than rectangular bricks.} \item{increment_level}{Default '0'. Use in animations. Shift Level/z dimension by an integer.} diff --git a/man/bricks_from_excel.Rd b/man/bricks_from_excel.Rd index 3ddb127..cabb414 100644 --- a/man/bricks_from_excel.Rd +++ b/man/bricks_from_excel.Rd @@ -6,6 +6,7 @@ \usage{ bricks_from_excel( excel_table, + piece_table = NULL, repeat_levels = 1, increment_level = 0, max_level = Inf, @@ -20,6 +21,8 @@ bricks_from_excel( \arguments{ \item{excel_table}{Sheet imported from a brickr Excel template to build model. Contains stud placement and colors.} +\item{piece_table}{Sheet identical in shape to \code{excel_table} with piece shape IDs.} + \item{repeat_levels}{How many times to repeat a level. Can save time in model planning. Default is 1.} \item{increment_level}{Default '0'. Use in animations. Shift Level/z dimension by an integer.} diff --git a/man/bricks_from_table.Rd b/man/bricks_from_table.Rd index 5300f18..a26eaa4 100644 --- a/man/bricks_from_table.Rd +++ b/man/bricks_from_table.Rd @@ -7,6 +7,7 @@ bricks_from_table( matrix_table, color_guide = brickr::lego_colors, + piece_matrix = NULL, .re_level = TRUE, increment_level = 0, max_level = Inf, @@ -19,10 +20,12 @@ bricks_from_table( ) } \arguments{ -\item{matrix_table}{A data frame of a 3D brick model desigh. Left-most column is level/height/z dimension, with rows as Y axis and columns as X axis. See example. Use \code{tribble} for ease.} +\item{matrix_table}{A data frame of a 3D brick model design. Left-most column is level/height/z dimension, with rows as Y axis and columns as X axis. See example. Use \code{tribble} for ease.} \item{color_guide}{A data frame linking numeric \code{.value} in \code{matrix_table} to official LEGO color names. Defaults to data frame 'lego_colors'.} +\item{piece_matrix}{A data frame in same shape as \code{matrix_table} with piece shape IDs.} + \item{.re_level}{Logical to reassign the Level/z dimension to layers in alphanumeric order. Set to FALSE to explicitly provide levels.} \item{increment_level}{Default '0'. Use in animations. Shift Level/z dimension by an integer.}