% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/plot-mesh-dotcloud.R
\name{plot_mesh_dotcloud}
\alias{plot_mesh_dotcloud}
\title{Render one or more meshes as an orthographic dot cloud in base R}
\usage{
plot_mesh_dotcloud(
  mesh,
  eye = c(0, 0, 1000),
  lookat = c(0, 0, 0),
  up = c(0, 1, 0),
  col = c("white", "gray30"),
  pch = 16L,
  cex = 0.1,
  add = FALSE,
  axes = FALSE,
  asp = 1,
  xlim = NULL,
  ylim = NULL,
  zoom = 1,
  xlab = "",
  ylab = "",
  normal_weight = c("auto", "area", "angle"),
  side = c("front", "back", "both"),
  mesh_clipping = 0.7,
  alpha = 1,
  clipping_plane = NULL,
  clipping_plane_enabled = TRUE,
  ...
)
}
\arguments{
\item{mesh}{a \code{'mesh3d'} object, or a list of \code{'mesh3d'} objects.
Meshes without a face matrix (\code{$it}) are treated as point clouds.
If \code{mesh$normals} is absent and the mesh has faces, normals are
recomputed with \code{\link{vcg_update_normals}}.}

\item{eye}{numeric vector of length 3 - camera position in world space.}

\item{lookat}{numeric vector of length 3 - the world-space point the camera
is looking at.}

\item{up}{numeric vector of length 3 - a world-space vector indicating
which direction is "up" for the camera; defaults to \code{c(0, 1, 0)}.}

\item{col}{base color(s) for the dots.  Accepted forms:
\itemize{
  \item A single color string - applied to all meshes.
  \item A character vector of length 2 or more (not matching any vertex
    count) - used as a depth-ordered color gradient applied to all meshes.
  \item A character vector of length equal to the number of vertices in a
    single mesh - per-vertex colors for that mesh.
  \item A list of length equal to the number of meshes - each element is
    one of the above, applied to the corresponding mesh.
}
Default \code{"gray30"}.}

\item{pch}{point character; a scalar or vector/list with one value per mesh,
recycled as necessary.  Default \code{16L}.}

\item{cex}{point expansion factor; a scalar or vector/list with one value
per mesh, recycled as necessary.  Default \code{0.1}.}

\item{add}{logical; if \code{TRUE} the dots are added to an existing plot
instead of opening a new one.  Default \code{FALSE}.}

\item{axes}{logical; whether to draw axes on a new plot.  Ignored when
\code{add = TRUE}.  Default \code{FALSE}.}

\item{asp}{aspect ratio of the new plot; default \code{1} (equal scaling).
Ignored when \code{add = TRUE}.}

\item{xlim, ylim}{axis limits for the new plot; \code{NULL} (default) lets R
choose automatically from all meshes' projected vertices.  Ignored when
\code{add = TRUE}.}

\item{zoom}{positive numeric magnification applied to the auto-computed
axis limits when \code{xlim} or \code{ylim} is \code{NULL}.  Values
greater than \code{1} zoom in, values in \code{(0, 1)} zoom out.
When \code{asp} is set, the zoom is plot-region aware (queried via
\code{par("pin")}): the axis that already fills the device after
\code{asp}-induced expansion is zoomed by exactly \code{zoom}, and
the other axis is zoomed less so the data fills more of the plot
region while preserving the requested \code{asp}.  Ignored for any
axis whose limit was supplied explicitly, and when \code{add = TRUE}.
Default \code{1}.}

\item{xlab, ylab}{axis labels for the new plot.  Ignored when
\code{add = TRUE}.}

\item{normal_weight}{passed to \code{\link{vcg_update_normals}} when normals
must be recomputed; one of \code{"auto"} (area if no normals present,
otherwise skip), \code{"area"}, or \code{"angle"}.  Default \code{"auto"}.}

\item{side}{which side of meshed surfaces to render.  One of \code{"front"}
(default), \code{"back"}, or \code{"both"} (renders all vertices).  Point clouds are always
rendered regardless of this setting.}

\item{mesh_clipping}{numeric in \code{[0, 1]} controlling how much of
the surface is kept relative to the camera-facing direction.
Vertices whose rim-light weight (\eqn{1 - |n \cdot z_{cam}|}) is at
or below \code{1 - mesh_clipping} are dropped, leaving only the
silhouette/grazing band.  \code{mesh_clipping = 1} (no clipping)
keeps all vertices; smaller values peel away more of the
front/back-facing dots.  Surviving vertices are drawn opaque, and
their \code{cex} is multiplied by the rim-light weight so
grazing-edge dots appear larger than near-front-facing dots.
Drawing opaque points with size-modulated weight is dramatically
faster than R's true per-point transparency.  Default \code{0.7}.}

\item{alpha}{numeric in \code{[0, 1]}; one value per mesh (recycled),
sets the transparency of each mesh (\code{1} = fully opaque,
\code{0} = fully transparent).  Vertices belonging to a mesh with
\code{alpha = 0} are dropped entirely.  Default \code{1}.}

\item{clipping_plane}{optional list of world-space clipping planes used to
hide parts of the scene.  Each plane is a numeric vector of length 5:
the first three entries are the plane normal \eqn{(n_x, n_y, n_z)}
(must be non-zero; normalized internally), the fourth is the signed
distance from the world origin to the plane along that normal (so the
plane equation is \eqn{n \cdot x = d}), and the fifth indicates which
half-space is kept: \code{1} keeps the front side (the side the normal
points to), \code{-1} keeps the back side, and \code{0} keeps whichever
side currently faces the camera (auto-flipped per call based on
\code{eye}).  Multiple planes are intersected.  Clipping is applied
per vertex.  A single length-5 numeric vector is also accepted as
shorthand for a one-plane list.  Default \code{NULL} (no clipping).}

\item{clipping_plane_enabled}{logical vector, one entry per mesh
(recycled), controlling whether \code{clipping_plane} is applied to
that mesh.  \code{TRUE} (default) means the mesh participates in
clipping; \code{FALSE} exempts the mesh entirely (all of its vertices
are kept regardless of the clipping planes).  Has no effect when
\code{clipping_plane} is \code{NULL}.}

\item{...}{additional graphical parameters forwarded to
\code{\link[graphics]{plot.default}} (new plot) or
\code{\link[graphics]{points}} (when \code{add = TRUE}).}
}
\value{
Invisibly returns a list with components \code{xlim} and
  \code{ylim} (the plot limits used).
}
\description{
Projects mesh vertices onto a 2D plane using an orthographic camera defined
by an eye position, a look-at point, and an up direction, then draws the
projected dots with base-R \code{\link[graphics]{plot}}.  Each dot is
rendered opaque, but its \code{cex} is modulated by a rim-light weight
\eqn{1 - |n \cdot z_{cam}|}: front- and back-facing vertices shrink toward
zero size, while grazing-edge vertices keep their full size.  This
size-modulated trick gives a rim-light look without paying R's per-point
transparency-blending cost.

Multiple meshes share a single depth space: all vertices are projected
together and sorted globally by depth before a single \code{plot()} call,
so the painter's algorithm works correctly across meshes.  Meshes without
faces (point clouds) are rendered at full size and are not affected
by the \code{side} filter.
}
\section{Coercing Surface Inputs}{

The surface objects are converted to \code{'mesh3d'} object before
applying further calculations.

When \code{surface} is a surface \pkg{ieegio} object, the returned
\code{mesh3d$vb} contains vertices that have been left-multiplied by
\code{surface$geometry$transforms[[1]]} (the first transform stored in the
geometry, typically the \code{ScannerAnat} or voxel-to-world transform).

\strong{Breaking change:} Earlier versions (before 0.2.6) of \pkg{ravetools}
returned the raw \code{surface$geometry$vertices} without applying any
transform, so downstream code often multiplied by
\code{surface$geometry$transforms[[1]]} (or an equivalent) manually before
working in world space. Such code will now \emph{double}
apply the transform and produce incorrect coordinates. If you previously
applied a transform from \code{surface$geometry$transforms} by hand after
calling a \pkg{ravetools} mesh function on an \code{'ieegio_surface'},
remove that manual step.

Surfaces with an empty or missing \code{geometry$transforms} list (for
example, surfaces produced by \pkg{ieegio}'s \code{volume_to_surface},
which stores an identity transform) are unaffected.

If \code{geometry$transforms} contains multiple transforms targeting
different coordinate spaces, only the first one is used. Callers that need
a specific target space should select and apply that transform themselves
before calling \pkg{ravetools} mesh functions.
}

\examples{

mesh <- vcg_isosurface(left_hippocampus_mask)

# Side view - rim-light shows the outline of the hippocampus
plot_mesh_dotcloud(
  mesh,
  eye = c(150, 0, 0),
  lookat = c(0, 0, 0),
  up = c(0, 0, 1),
  col = "steelblue",
  cex = 2
)

# Two meshes: surface + electrode point cloud
n_elec <- 20
electrodes <- structure(
  list(vb = matrix(rnorm(3 * n_elec, sd = 5), 3, n_elec) +
         rowMeans(mesh$vb)[1:3]),
  class = "mesh3d"
)
plot_mesh_dotcloud(
  mesh  = list(mesh, electrodes),
  eye    = c(150, 0, 0),
  lookat = c(0, 0, 0),
  up     = c(0, 0, 1),
  col    = list("steelblue", "red"),
  pch    = c(16L, 17L),
  cex    = c(2, 1.2)
)

}
\seealso{
\code{\link{vcg_update_normals}}, \code{\link{vcg_isosurface}}
}
