Turns a coarse list of waypoints into a dense, smooth path, which is what the
path-taking geometry functions expect: generate_tube sweeps a
cross-section along a path, and line_layer draws one straight
segment per consecutive pair of points. Handing a handful of control points
to those gives a visibly faceted tube and a polygonal line; this is how you
get the smooth version.
Usage
spline_path(
points,
method = c("catmull-rom", "bspline"),
samples_per_segment = 8L,
closed = FALSE,
alpha = 0.5
)Arguments
- points
Nx3 numeric matrix of points the curve has to pass through (or a length-3 vector for a single point). An open curve needs at least 2 points, a closed one at least 3 (
"bspline": at least 4).- method
Either
"catmull-rom"(interpolating, default) or"bspline"(approximating, smoother; see the description).- samples_per_segment
Number of points to generate per segment between two input points (default 8, clamped to at least 1). This is the knob that controls how smooth the result looks when rendered.
- closed
Whether the curve loops back to its first point (default
FALSE). A closed path ends on a copy of its first point.- alpha
Parameterization exponent of the Catmull-Rom curve (default
0.5, see the description). Ignored for"bspline".
Value
An Nx3 numeric matrix of path points, ready for
generate_tube, generate_tubes,
line_layer or camera_auto. An empty (0-row)
matrix if there are not enough distinct points for the chosen curve.
Details
Two curves are available, and they differ in a way that matters:
"catmull-rom"(the default) **interpolates**: the curve passes through every input point, and each point's tangent is derived from its two neighbours. This is what you want when the input points are positions that the curve has to hit (measured or digitized data)."bspline"**approximates**: the points act as a control cage that the curve stays inside, which irons out noise instead of reproducing it, and the curve is \(C^2\) continuous everywhere. It generally does not pass through the input points.
For the Catmull-Rom curve, alpha selects the parameterization and is
the knob that matters most on real data:
0.5(default) — *centripetal*. Knot intervals grow with the square root of the chord length, which prevents the cusps, loops and self-intersections that the uniform curve produces when the spacing of the input points is uneven (long segment followed by a short one, the norm for measured data).1— chord length: still free of cusps, but can overshoot more.0— uniform: the textbook curve, exact on evenly spaced points and misbehaving on everything else.
Examples
waypoints <- matrix(c(0, 0, 0, 1, 1, 0, 2, 0, 0, 3, 1, 0),
ncol = 3, byrow = TRUE)
path <- spline_path(waypoints, samples_per_segment = 8)
nrow(path) # 3 segments * 8 samples + the final point
#> [1] 25
# A smooth tube through the waypoints, instead of a faceted one:
mesh <- generate_tube(waypoints, radius = 0.1)
smooth <- generate_tube(path, radius = 0.1)
# An approximating (noise-reducing) closed loop:
loop <- spline_path(waypoints, method = "bspline", closed = TRUE)