View source: R/vcg-collision.R
| vcg_detect_collision | R Documentation |
Reports, for every element of y, whether it comes within
radius of x, together with the exact minimum distance. Each
side may be a point cloud, a set of connected line segments (for example
diffusion streamlines or an electrode shaft), or a triangular mesh, so the
function covers all nine pairings with one call.
The test is exact: it produces neither false negatives nor false positives,
and distance is the true minimum distance rather than a
vertex-sampled approximation.
vcg_detect_collision(
x,
y,
mode_x = c("auto", "points", "segments", "mesh"),
mode_y = c("auto", "points", "segments", "mesh"),
radius = 0,
early_stop = FALSE,
include_interior = FALSE
)
x |
the geometry that gets indexed; a matrix with |
y |
the geometry that gets queried; results are aligned to this side.
Same accepted types as |
mode_x, mode_y |
how to interpret |
radius |
distance tolerance; a collision is reported when the minimum
distance is at most |
early_stop |
whether to stop as soon as a collision is found, scanning
independently within each group of |
include_interior |
whether geometry lying strictly inside a closed
|
x is indexed once into a uniform spatial grid and y is
streamed against it, so put the larger or repeatedly-reused geometry in
x and the geometry you want per-element answers about in y.
Several chains share one matrix and are delimited by rows of NA; any
row that is not fully finite is treated as a separator. This lets a whole
bundle of streamlines be passed as a single matrix:
rbind(
c(0, 0, 0), c(1, 0, 0), c(2, 0, 0), # first streamline
c(NA, NA, NA), # separator
c(0, 5, 0), c(1, 5, 0) # second streamline
)
Those separators also define the unit that early_stop works on: it
stops once per group, so a bundle of streamlines yields at most one hit per
streamline.
When mode_y = 'segments', row i of the result describes the
segment running from row i to row i + 1.
Both geometries must already share one coordinate space. Surface
coordinates, volume IJK indices, and scanner coordinates are all
different spaces, and no transform is applied here.
include_interior relies on ray casting and therefore needs x
to be watertight with coherently oriented faces; see
vcg_fix_defects to repair a surface that is not.
Multi-threading follows ravetools_threads. The interior test
always runs single-threaded.
A list of three vectors, each aligned one-to-one with the rows of
y (or with the faces of y when mode_y = 'mesh'):
hitlogical. NA marks an element with nothing to
test: a separator row, or the final vertex of each group when
mode_y = 'segments'. When early_stop = TRUE, NA
also marks elements the scan never reached
distancethe exact minimum distance where hit is
TRUE, and NA everywhere else. Distances beyond
radius are never computed, so a FALSE element carries no
distance
index1-based index of the closest element of x
within radius: a row when mode_x is 'points', the
row where the segment starts when 'segments', or a face column
when 'mesh'. NA where there is no collision
The surface objects are converted to 'mesh3d' object before
applying further calculations.
When surface is a surface ieegio object, the returned
mesh3d$vb contains vertices that have been left-multiplied by
surface$geometry$transforms[[1]] (the first transform stored in the
geometry, typically the ScannerAnat or voxel-to-world transform).
Breaking change: Earlier versions (before 0.2.6) of ravetools
returned the raw surface$geometry$vertices without applying any
transform, so downstream code often multiplied by
surface$geometry$transforms[[1]] (or an equivalent) manually before
working in world space. Such code will now double
apply the transform and produce incorrect coordinates. If you previously
applied a transform from surface$geometry$transforms by hand after
calling a ravetools mesh function on an 'ieegio_surface',
remove that manual step.
Surfaces with an empty or missing geometry$transforms list (for
example, surfaces produced by ieegio's volume_to_surface,
which stores an identity transform) are unaffected.
If 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 ravetools mesh functions.
library(ravetools)
# A spherical region of interest
roi <- vcg_sphere()
# Two streamlines in one matrix, separated by an NA row: the first passes
# through the sphere, the second stays well clear of it
streamlines <- rbind(
cbind(seq(-3, 3, by = 0.5), 0, 0),
c(NA, NA, NA),
cbind(seq(-3, 3, by = 0.5), 5, 0)
)
result <- vcg_detect_collision(
x = roi,
y = streamlines,
mode_y = "segments",
radius = 0.1
)
# Which segments touch the sphere, and how close do they get?
data.frame(
hit = result$hit,
distance = round(result$distance, 4)
)
# A point cloud against the same region, asking only for proximity
points <- rbind(c(0, 0, 0), c(1.05, 0, 0), c(10, 10, 10))
vcg_detect_collision(roi, points, radius = 0.1)$hit
# The centre of the sphere is far from its surface, so it only counts as a
# collision when the interior is included
vcg_detect_collision(roi, rbind(c(0, 0, 0)), radius = 0.1)$hit
vcg_detect_collision(roi, rbind(c(0, 0, 0)), radius = 0.1,
include_interior = TRUE)$hit
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.