--- title: "Custom boids4R Corridor Workflow" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Custom boids4R Corridor Workflow} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_knit$set(purl = FALSE) ggwebgl_truthy <- function(x) { tolower(x) %in% c("1", "true", "yes", "y") } ggwebgl_ci_vars <- c( "CI", "GITHUB_ACTIONS", "GITLAB_CI", "BUILDKITE", "TRAVIS", "APPVEYOR", "CIRCLECI", "JENKINS_URL" ) ggwebgl_is_ci <- any(vapply(Sys.getenv(ggwebgl_ci_vars), ggwebgl_truthy, logical(1))) ggwebgl_is_check <- nzchar(Sys.getenv("_R_CHECK_PACKAGE_NAME_")) ggwebgl_eval_code <- !ggwebgl_is_ci && !ggwebgl_is_check && ( ggwebgl_truthy(Sys.getenv("NOT_CRAN")) || ggwebgl_truthy(Sys.getenv("GGWEBGL_EVAL_COVERAGE_VIGNETTE")) ) ggwebgl_eval_widgets <- ggwebgl_eval_code && ggwebgl_truthy(Sys.getenv("GGWEBGL_EVAL_LIVE_WIDGETS")) knitr::opts_chunk$set(collapse = TRUE, comment = "#>", eval = ggwebgl_eval_code) if (file.exists("../DESCRIPTION") && requireNamespace("pkgload", quietly = TRUE)) { pkgload::load_all("..", export_all = FALSE, helpers = FALSE, quiet = TRUE) } else { library(ggWebGL) } boids4r_available <- requireNamespace("boids4R", quietly = TRUE) ``` # Custom Corridor Workflow This workflow builds a 2D corridor from low-level `boids4R` constructors, then compares a baseline run with a stronger obstacle/predator avoidance run. The visual encoding is the same as the scenario pages: current boids are emphasized, recent trails are faint, velocity vectors use species colours, and obstacles are shown as rings. Live WebGL widgets are disabled during CRAN, package checks, and CI. Rich local or pkgdown rendering requires `GGWEBGL_EVAL_COVERAGE_VIGNETTE=true` and `GGWEBGL_EVAL_LIVE_WIDGETS=true`. ```{r, eval = ggwebgl_eval_code} if (!boids4r_available) { cat("boids4R is unavailable, so live custom corridor widgets are skipped.\n") } else if (!ggwebgl_eval_widgets) { cat("boids4R is available, but live custom corridor widgets are skipped because live widget evaluation is disabled.\n") } else { cat("boids4R is available; live custom corridor widgets will be rendered below.\n") } ``` ```{r, include = FALSE, eval = ggwebgl_eval_code} simulate_custom_corridor <- function(stronger_avoidance = FALSE, seed = 221L) { bounds <- matrix( c(-2.4, -1.35, 2.4, 1.35), ncol = 2, dimnames = list(c("x", "y"), c("min", "max")) ) n_school <- 96L n_scout <- 32L n_boids <- n_school + n_scout school_axis <- seq(0, 1, length.out = n_school) scout_axis <- seq(0, 1, length.out = n_scout) positions <- rbind( cbind(-2.18 + 0.83 * school_axis, -0.70 + 0.95 * abs(sin(pi * school_axis))), cbind(-2.22 + 0.77 * scout_axis, 0.28 + 0.64 * abs(cos(pi * scout_axis))) ) velocity_phase <- seq(0, 2 * pi, length.out = n_boids) velocities <- cbind( 0.35 + 0.20 * cos(velocity_phase), 0.08 * sin(velocity_phase) ) custom_state <- boids4R::boids_state( n_boids, "2d", bounds = bounds, positions = positions, velocities = velocities, species = c(rep("school", n_school), rep("scout", n_scout)) ) custom_world <- boids4R::boids_world( "2d", bounds = bounds, boundary = "reflect", obstacles = data.frame( x = c(-0.82, -0.05, 0.72), y = c(0.42, -0.36, 0.48), radius = c(0.30, 0.36, 0.31) ), predators = data.frame( x = -0.25, y = 0.92, radius = 0.58, strength = 1.2 ), attractors = data.frame( x = 2.08, y = -0.86, strength = 0.95 ) ) params <- boids4R::boids_params( "2d", separation_weight = 1.35, alignment_weight = 0.94, cohesion_weight = 0.62, obstacle_weight = if (isTRUE(stronger_avoidance)) 2.8 else 2.5, predator_weight = if (isTRUE(stronger_avoidance)) 3.2 else 2.3, goal_weight = if (isTRUE(stronger_avoidance)) 0.20 else 0.16, max_speed = 1.18, max_force = 0.12, noise = 0.001 ) boids4R::simulate_boids( custom_state, custom_world, params, steps = 240L, record_every = 3L, seed = seed ) } render_custom_corridor <- function(name, stronger_avoidance = FALSE, seed = 221L) { sim <- simulate_custom_corridor(stronger_avoidance = stronger_avoidance, seed = seed) spec <- ggWebGL:::ggwebgl_boids_display_spec( sim, boid_size = 4.4, prey_size = 5.0, predator_size = 8.0, current_alpha = 0.96, trail_alpha = 0.18, vector_mode = "current", vector_colour_mode = "species", vector_every = 1L, vector_alpha = 0.68, vector_width = 1.25, vector_scale = 0.14, obstacle_mode = "ring", obstacle_segments = 48L, obstacle_alpha = 0.9, trail = "recent", trail_length = 32L, shader = "default", speed = 1.5, fps = 24L ) spec$labels$title <- paste("boids4R custom corridor:", name) ggWebGL::ggWebGL(spec, height = 500) } ``` ## Baseline Corridor ```{r baseline-corridor, eval = ggwebgl_eval_widgets} if (!boids4r_available) { cat("Baseline corridor widget skipped.\n") } else { render_custom_corridor("baseline", stronger_avoidance = FALSE, seed = 221L) } ``` ## Stronger Avoidance Corridor ```{r stronger-avoidance-corridor, eval = ggwebgl_eval_widgets} if (!boids4r_available) { cat("Stronger avoidance corridor widget skipped.\n") } else { render_custom_corridor("stronger_avoidance", stronger_avoidance = TRUE, seed = 222L) } ```