% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/geom-hull-3d.R
\name{geom_hull_3d}
\alias{geom_hull_3d}
\alias{stat_hull_3d}
\title{3D convex and alpha hulls}
\usage{
geom_hull_3d(
  mapping = NULL,
  data = NULL,
  stat = StatHull3D,
  position = "identity",
  ...,
  method = "convex",
  radius = NULL,
  singular = FALSE,
  light = NULL,
  cull_backfaces = TRUE,
  sort_method = NULL,
  scale_depth = TRUE,
  inherit.aes = TRUE,
  show.legend = TRUE
)

stat_hull_3d(
  mapping = NULL,
  data = NULL,
  geom = GeomPolygon3D,
  position = "identity",
  ...,
  method = "convex",
  radius = NULL,
  singular = FALSE,
  light = NULL,
  cull_backfaces = TRUE,
  sort_method = NULL,
  scale_depth = TRUE,
  inherit.aes = TRUE,
  show.legend = TRUE
)
}
\arguments{
\item{mapping}{Set of aesthetic mappings created by \code{\link[=aes]{aes()}}. The required
aesthetics are \code{x}, \code{y}, and \code{z}. Additional aesthetics can use computed
variables with \code{\link[ggplot2:after_stat]{ggplot2::after_stat()}}.}

\item{data}{The data to be displayed in this layer.}

\item{stat}{The statistical transformation to use on the data. Defaults to \code{StatHull3D}.}

\item{position}{Position adjustment, defaults to "identity". To collapse the result
onto one 2D surface, use \code{position_on_face()}.}

\item{...}{Other arguments passed on to the layer function (typically GeomPolygon3D), such as
aesthetics like \code{colour}, \code{fill}, \code{linewidth}, \code{annotate = annotate_3d(...)}, etc.}

\item{method}{Triangulation method. Either:
\itemize{
\item \code{"convex"}: Convex hull triangulation (default). Requires the \pkg{geometry} package.
\item \code{"alpha"}: Alpha shape triangulation (can capture non-convex topologies)
}}

\item{radius}{The "alpha" parameter when alpha method is used.
A face is included in the resulting alpha shape if it can be "exposed" by a sphere of this radius.
If NULL (the default), a simple heuristic based on the data scale is used to calculate a radius value.
Note that alpha shapes are quite sensitive to the coordinate scales of your data. See Details section.}

\item{singular}{Whether to include "singular" faces when \code{method = "alpha"}.
These are faces that do not bound any enclosed volume, appearing as isolated
sheets dangling from the surface, and are usually a sign that \code{radius} is
slightly too small. Because they enclose nothing, they have no well-defined
outward direction: their lighting is arbitrary and they are never culled.
Defaults to \code{FALSE}.}

\item{light}{A lighting specification object created by \code{\link[=light]{light()}}, \code{light("none")}
or the string \code{"none"} to disable lighting, or \code{NULL} to inherit plot-level
lighting. Set plot-level lighting by adding \code{\link[=light]{light()}} to the plot, and
layer-specific lighting via the \code{light} argument of \verb{geom_*_3d()} functions,
which takes precedence.}

\item{cull_backfaces}{Logical indicating whether to remove back-facing polygons
from rendering. This is primarily for performance optimization but may be useful
for aesthetic reasons in some situations. Backfaces are determined using
screen-space winding order after 3D transformation. Defaults vary by geometry
type: FALSE for open surface-type geometries, TRUE for solid objects (hulls,
voxels, etc. where backfaces are generally hidden unless frontfaces are transparent
or explicitly disabled).}

\item{sort_method}{Depth sorting algorithm. See \link{sorting_methods} for details.}

\item{scale_depth}{Controls whether polygon linewidths are scaled to make closer lines
wider and farther lines narrower, based on the mean depth of a polygon. \code{TRUE}
(the default) applies full scaling and \code{FALSE} disables it; a number sets the
strength directly, where \code{1} matches \code{TRUE}, \code{0} matches \code{FALSE}, values below
1 subdue the effect and values above 1 exaggerate it. This affects the layer
only; use \code{coord_3d(scale_depth = )} for gridlines, cube borders, axis ticks,
and axis text.}

\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics.}

\item{show.legend}{Logical indicating whether this layer should be included in legends.}

\item{geom}{The geometric object used to display the data. Defaults to \code{GeomPolygon3D.}}
}
\value{
A \code{Layer} object that can be added to a ggplot.
}
\description{
Turns 3D point clouds into surface hulls consisting of triangular polygons,
using either convex hull or alpha shape algorithms.
}
\section{Grouping}{

Hulls respect ggplot2 grouping aesthetics. To create separate hulls for different
subsets of your data, use \code{aes(group = category_variable)} or similar grouping aesthetics.
Each group will get its own independent hull.
}

\section{Alpha scale sensitivity}{

Alpha shape method is highly sensitive to coordinate scales. \code{radius} is expressed
in data units, so a value that works for data scaled 0-1 will likely fail for data
scaled 0-1000.
Guidelines for choosing radius:
\itemize{
\item Start at a small fraction of your data's overall extent and adjust based on results
\item For data with mixed scales (e.g., x: 0-1, y: 0-1000), consider rescaling your data first
\item Larger radius values → smoother, more connected surfaces
\item Smaller radius values → more detailed surfaces, but may fragment
\item If you get no triangles, try increasing radius by 10x
\item If surface fills unwanted holes, try decreasing radius by 10x
}
}

\section{Aesthetics}{

\code{stat_hull_3d()} requires the following aesthetics:
\itemize{
\item \strong{x}: X coordinate
\item \strong{y}: Y coordinate
\item \strong{z}: Z coordinate
}
}

\section{Computed variables}{

\itemize{
\item \code{normal_x}, \code{normal_y}, \code{normal_z}: Surface normal components
}
}

\examples{
\dontshow{if (requireNamespace("geometry", quietly = TRUE)) withAutoprint(\{ # examplesIf}
# A solid torus: a shape whose hole a convex hull cannot represent
set.seed(1)
n <- 2000
theta <- runif(n, 0, 2 * pi)  # position around the ring
phi <- runif(n, 0, 2 * pi)    # position around the tube
rho <- sqrt(runif(n))         # distance from the tube center
torus <- data.frame(
  x = (3 + rho * cos(phi)) * cos(theta),
  y = (3 + rho * cos(phi)) * sin(theta),
  z = rho * sin(phi)
)

# Convex hull: the hole is bridged over
ggplot(torus, aes(x, y, z)) +
  geom_hull_3d(method = "convex", fill = "gray40") +
  coord_3d(scales = "fixed")

# Alpha shape: the hole is preserved
\donttest{
ggplot(torus, aes(x, y, z)) +
  geom_hull_3d(method = "alpha", radius = 0.6, fill = "gray40") +
  coord_3d(scales = "fixed")
}

# Use `cull_backfaces = FALSE` to render far side of hull
\donttest{
ggplot(torus, aes(x, y, z)) +
  geom_hull_3d( # default culling for comparison
    method = "alpha", radius = 0.6, light = NULL,
    fill = "steelblue", color = "darkred", linewidth = .5, alpha = .5) +
  geom_hull_3d( # culling disabled
    aes(x = x + 9), cull_backfaces = FALSE,
    method = "alpha", radius = 0.6, light = NULL,
    fill = "steelblue", color = "darkred", linewidth = .5, alpha = .5) +
  coord_3d(scales = "fixed")
}

# Use grouping to build separate hulls for data subsets
ggplot(iris, aes(Petal.Length, Sepal.Length, Sepal.Width,
                 color = Species, fill = Species)) +
      geom_hull_3d() +
      coord_3d(scales = "fixed")
\dontshow{\}) # examplesIf}
}
\seealso{
\code{\link[=coord_3d]{coord_3d()}} for 3D coordinate systems, \link{geom_polygon_3d} for the
default geometry with depth sorting, \code{\link[=light]{light()}} for lighting specifications.
}
