Trimmed faces are cut into four-sided patches (squares around holes, butterflies for round faces, motorcycle traces from concave corners) and each is meshed as a Coons grid, with a cut grid as the fallback; cells are at most 2:1 along straight directions. Folded blends are refused rather than overlapped. The README lists display meshes and the gpu crate.
This commit is contained in:
1 parent
e519fbd14d
commit
e3459edea8
11 files changed
+2068
-38
No files matched your search
@@ -135,6 +135,69 @@ pub(crate) fn triangulate(boundary: &[[f64; 2]], loops: &[std::ops::Range<usize>
|
||||
Some((extra, tris))
|
||||
}
|
||||
|
||||
/// The band between a face's boundary `loops` (ranges of the first `n` points of `points`) and
|
||||
/// the staircase around a block of grid cells inside it (`stairs`, sides between grid points
|
||||
/// of `points`): a constrained Delaunay triangulation of both with no point added, keeping the
|
||||
/// faces inside the boundary and outside the block (an odd number of constraints from the
|
||||
/// outside). Distances in the metric `scale`. Triangles counter-clockwise in (u, v), indices
|
||||
/// into `points`; `None` when a constraint cannot be kept (the staircase meets the boundary).
|
||||
pub(crate) fn band(points: &[[f64; 2]], n: usize, loops: &[std::ops::Range<usize>], stairs: &[(u32, u32)], scale: [f64; 2]) -> Option<Vec<[u32; 3]>> {
|
||||
let to = |p: &[f64; 2]| spade::mitigate_underflow(Point2::new(p[0] * scale[0], p[1] * scale[1]));
|
||||
let mut cdt = Cdt::new();
|
||||
let mut index: HashMap<FixedVertexHandle, u32> = HashMap::new();
|
||||
let mut handle: HashMap<u32, FixedVertexHandle> = HashMap::new();
|
||||
let mut add = |cdt: &mut Cdt, i: u32| -> Option<FixedVertexHandle> {
|
||||
if let Some(h) = handle.get(&i) {
|
||||
return Some(*h);
|
||||
}
|
||||
let p = points.get(i as usize)?;
|
||||
if !p.iter().all(|x| x.is_finite()) {
|
||||
return None;
|
||||
}
|
||||
let h = cdt.insert(to(p)).ok()?;
|
||||
// Two points at one place (pole copies) share a vertex: the first index names it.
|
||||
index.entry(h).or_insert(i);
|
||||
handle.insert(i, h);
|
||||
Some(h)
|
||||
};
|
||||
let mut sides: Vec<(FixedVertexHandle, FixedVertexHandle)> = Vec::new();
|
||||
for r in loops {
|
||||
let len = r.len();
|
||||
for k in 0..len {
|
||||
let (a, b) = (u32::try_from(r.start + k).ok()?, u32::try_from(r.start + (k + 1) % len).ok()?);
|
||||
if (a as usize) >= n || (b as usize) >= n {
|
||||
return None;
|
||||
}
|
||||
sides.push((add(&mut cdt, a)?, add(&mut cdt, b)?));
|
||||
}
|
||||
}
|
||||
for &(a, b) in stairs {
|
||||
sides.push((add(&mut cdt, a)?, add(&mut cdt, b)?));
|
||||
}
|
||||
for (a, b) in sides {
|
||||
if a == b || cdt.exists_constraint(a, b) {
|
||||
continue;
|
||||
}
|
||||
if !cdt.can_add_constraint(a, b) {
|
||||
return None;
|
||||
}
|
||||
cdt.add_constraint(a, b);
|
||||
}
|
||||
let region = region(&cdt);
|
||||
let mut tris = Vec::new();
|
||||
for face in cdt.inner_faces() {
|
||||
if !region.get(face.index()).copied().unwrap_or(false) {
|
||||
continue;
|
||||
}
|
||||
let mut t = [0u32; 3];
|
||||
for (slot, v) in t.iter_mut().zip(face.vertices()) {
|
||||
*slot = *index.get(&v.fix())?;
|
||||
}
|
||||
tris.push(t);
|
||||
}
|
||||
Some(tris)
|
||||
}
|
||||
|
||||
/// Insert the parameters of the surface point under every triangle centre that lies more than
|
||||
/// the tolerance from the triangle or whose corner normals turn more than the facet angle, and
|
||||
/// under the middle of every non-constraint side that sags more than the tolerance or is
|
||||
|
||||
Reference in new issue
Block a user