| Title: | A Live Constrained Delaunay Mesh |
|---|---|
| Description: | A persistent, editable constrained Delaunay triangulation: add and remove points and segments at any time, refine toward quality targets, and read the mesh back as plain tables (vertices, triangles with constraint depth, segments). Built on the 'spade' Rust crate via extendr. The incremental sibling of 'cdtr'. |
| Authors: | Michael Sumner [aut, cre] |
| Maintainer: | Michael Sumner <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.0.0.9000 |
| Built: | 2026-10-15 00:46:27 UTC |
| Source: | https://github.com/hypertidy/trowel |
Points are added with mesh_add_points() (returning stable vertex ids;
a point at an existing vertex returns that vertex's id). Segments join
two vertex ids; a segment that crosses an existing constraint has the
crossing inserted as a new vertex, with attributes interpolated along the
new segment. Removing a point removes any segment through it; removing a
segment clears its constraint edges and leaves the vertices.
mesh_add_points(m, x, y, PA = NULL) mesh_add_segments(m, a, b) mesh_remove_points(m, ids) mesh_remove_segments(m, seg_ids)mesh_add_points(m, x, y, PA = NULL) mesh_add_segments(m, a, b) mesh_remove_points(m, ids) mesh_remove_segments(m, seg_ids)
m |
a mesh from |
x, y
|
coordinates of points to add |
PA |
attribute matrix for the new points (one row per point), or NULL |
a, b
|
vertex ids of segment endpoints |
ids |
vertex ids to remove |
seg_ids |
segment ids to remove |
vertex ids for mesh_add_points, segment ids for
mesh_add_segments, the mesh invisibly for the removals
A persistent constrained Delaunay triangulation that accepts edits at any time. Start empty or from the usual three tables: vertices, segments as index pairs, optional per-vertex attributes.
mesh_new(x = NULL, y = NULL, s0 = NULL, s1 = NULL, PA = NULL)mesh_new(x = NULL, y = NULL, s0 = NULL, s1 = NULL, PA = NULL)
x, y
|
vertex coordinates (may be omitted for an empty mesh) |
s0, s1
|
1-based indices into the vertices for constraint segments |
PA |
numeric matrix of per-vertex attributes (one row per vertex), or NULL; column names become attribute names |
a trowel handle (a mutable object: functions that edit it return
it invisibly)
x <- c(0, 1, 1, 0, 0.25, 0.75, 0.75, 0.25) y <- c(0, 0, 1, 1, 0.25, 0.25, 0.75, 0.75) m <- mesh_new(x, y, 1:8, c(2, 3, 4, 1, 6, 7, 8, 5)) mesh_counts(m) table(mesh_triangles(m)$depth)x <- c(0, 1, 1, 0, 0.25, 0.75, 0.75, 0.25) y <- c(0, 0, 1, 1, 0.25, 0.25, 0.75, 0.75) m <- mesh_new(x, y, 1:8, c(2, 3, 4, 1, 6, 7, 8, 5)) mesh_counts(m) table(mesh_triangles(m)$depth)
Read a live mesh as tables
mesh_vertices(m) mesh_triangles(m) mesh_segments(m) mesh_constraint_edges(m) mesh_edges(m) mesh_counts(m)mesh_vertices(m) mesh_triangles(m) mesh_segments(m) mesh_constraint_edges(m) mesh_edges(m) mesh_counts(m)
m |
a mesh |
data frames: mesh_vertices (id, x, y, origin, attribute columns;
origin is "input", "crossing" or "steiner"), mesh_triangles (v0, v1, v2
as vertex ids, depth = constraint crossings from outside), mesh_segments
(segment, position, vertex: the chain of vertex ids along each live
segment), mesh_constraint_edges and mesh_edges (a, b vertex ids);
mesh_counts is a list of sizes.
Delaunay refinement toward a minimum angle and/or a maximum triangle area, inserting Steiner vertices. Attributes on new vertices are interpolated linearly from the mesh as it was before refinement. Can be called again after further edits.
mesh_refine( m, min_angle = NULL, max_area = NULL, max_steiner = Inf, keep_constraints = FALSE, inner_only = TRUE )mesh_refine( m, min_angle = NULL, max_area = NULL, max_steiner = Inf, keep_constraints = FALSE, inner_only = TRUE )
m |
a mesh |
min_angle |
minimum angle in degrees (NULL for none; spade caps at 30) |
max_area |
maximum triangle area (NULL for none) |
max_steiner |
budget of Steiner vertices (Inf for unlimited) |
keep_constraints |
if TRUE constraint edges are never split |
inner_only |
if TRUE (default) the region outside every constraint (depth 0) is left as it was: Steiner vertices that would land there are dropped (vertices on boundary constraint edges stay, since they belong to both sides). Holes count as inside; filter by depth parity yourself if a hole should not be refined. FALSE refines every triangle in the hull. |
invisibly, a list with complete (did refinement finish within
budget), added (vertex count added) and new_ids
Convenience for plotting and for handing to code that wants 1-based
row indices into mesh_vertices() rather than ids.
mesh_T(m)mesh_T(m)
m |
a mesh |
integer matrix, 3 columns, rows index into mesh_vertices(m)
The live mesh.
TrowelTrowel
An object of class environment of length 12.
new
Create an empty mesh, with optional attribute column names.
add_points
Add points; returns their ids (an existing vertex at the same position is reused).
add_segments
Add constraint segments between existing vertex ids; crossings with existing constraints are resolved by inserting the crossing point. Returns segment ids.
remove_points
Remove vertices by id. Segments through them are removed too.
remove_segments
Remove segments by id (constraint flags cleared; vertices stay).
refine
Refine the mesh. Any argument may be NA to skip it.
vertices
Vertices: id, x, y, origin (0 input, 1 crossing, 2 steiner), attributes.
triangles
Triangles as vertex ids (3 columns) plus depth.
constraint_edges
Constraint edges currently in the mesh, as vertex id pairs.
edges
All edges as vertex id pairs.
segments
User segments: segment id and the chain of vertex ids along it.