Skip to content

Commit

Permalink
better triangulation api
Browse files Browse the repository at this point in the history
  • Loading branch information
Agapanthus committed Mar 6, 2024
1 parent 42e22de commit 3167ffb
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 164 deletions.
10 changes: 5 additions & 5 deletions editor/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ fn make_2d_shape(_settings: &MeshSettings) -> MeshVec3 {
}

fn make_mesh(settings: &MeshSettings) -> MeshVec3 {
make_2d_shape(settings)
// _make_spiral(settings)
// make_2d_shape(settings)
_make_spiral(settings)
//MeshVec3::octahedron(1.0)
}

Expand Down Expand Up @@ -201,9 +201,9 @@ fn setup_meshes(
Name::new("Generated Shape"),
));

show_vertex_indices(&mut texts, &mesh);
show_edges(&mut texts, &mesh, 0.1);
show_faces(&mut texts, &mesh);
//show_vertex_indices(&mut texts, &mesh);
//show_edges(&mut texts, &mesh, 0.1);
//show_faces(&mut texts, &mesh);

commands.spawn((
PbrBundle {
Expand Down
2 changes: 1 addition & 1 deletion src/representation/face/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{payload::Payload, Deletable, HalfEdge, IndexType, Mesh};
mod geometry;
mod iterator;
mod tesselate;
pub mod tesselate;

/// A face in a mesh.
///
Expand Down
24 changes: 16 additions & 8 deletions src/representation/face/tesselate/delaunay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,26 @@ where
E: IndexType,
F: IndexType,
{
fn delaunayfy<V: IndexType, P: Payload>(&self, mesh: &Mesh<E, V, F, P>, indices: &mut Vec<V>)
where
/// Flips edges until the delaunay-condition is met. This is quite slow: O(n^3).
pub fn delaunayfy<V: IndexType, P: Payload>(
&self,
mesh: &Mesh<E, V, F, P>,
indices: &mut Vec<V>,
local_indices: bool,
) where
P::Vec: Vector3D<P::S>,
{
let vs: Vec<(P::Vec2, V)> = self.vertices_2d::<V, P>(mesh).collect();
assert!(vs.len() == self.vertices(mesh).count());
assert!(vs.len() == self.num_vertices(mesh));
let mut vsh: HashMap<V, P::Vec2> = HashMap::new();
for (v, p) in vs {
vsh.insert(p, v);
if local_indices {
for (i, (v, p)) in vs.iter().enumerate() {
vsh.insert(V::new(i), *v);
}
} else {
for (v, p) in vs {
vsh.insert(p, v);
}
}

if indices.len() < 3 {
Expand Down Expand Up @@ -70,9 +81,6 @@ where
_indices: &mut Vec<V>,
) {
assert!(self.may_be_curved() || self.is_planar2(mesh));
// TODO: or at least some other O(n log n) algorithm: https://en.wikipedia.org/wiki/Delaunay_triangulation
}*/
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ where
{
/// Use ear-clipping to triangulate the face.
/// This is relatively slow: O(n^2).
///
/// Optionally randomize the start position to search the next ear.
/// This is slightly slower but can generate more versatile results.
pub fn ear_clipping<V: IndexType, P: Payload>(
&self,
mesh: &Mesh<E, V, F, P>,
indices: &mut Vec<V>,
local_coordinates: bool,
local_indices: bool,
randomize: bool,
) where
P::Vec: Vector3D<P::S>,
{
Expand All @@ -39,6 +43,9 @@ where
}
let mut clipped = vec![false; n0];
let mut i_a = 0;
if randomize {
i_a = rand::random::<usize>() % n0;
}
let mut n = n0;
let mut fails_since_advance = 0;
while n > 2 {
Expand Down Expand Up @@ -67,7 +74,7 @@ where
continue;
}

if local_coordinates {
if local_indices {
indices.push(V::new(i_a));
indices.push(V::new(i_b));
indices.push(V::new(i_c));
Expand All @@ -79,77 +86,11 @@ where
clipped[i_b] = true;
n -= 1;
fails_since_advance = 0;
}
}

/// Ear clipping, but randomly choose the start for the search of the next ear.
/// This is even slower than the normal ears, but it can be used to generate different triangulations.
pub fn ear_clipping_randomized<V: IndexType, P: Payload>(
&self,
mesh: &Mesh<E, V, F, P>,
indices: &mut Vec<V>,
) where
P::Vec: Vector3D<P::S>,
{
// TODO: ear clipping is inefficient
assert!(self.may_be_curved() || self.is_planar2(mesh));

let vs: Vec<(P::Vec2, V)> = self.vertices_2d::<V, P>(mesh).collect();

let triangle_empty = |a: usize, b: usize, c: usize| {
let av = vs[a].0;
let bv = vs[b].0;
let cv = vs[c].0;
vs.iter()
.enumerate()
.all(|(i, v)| i == a || i == b || i == c || !v.0.is_inside_triangle(av, bv, cv))
};

let n0 = vs.len();
if n0 < 3 {
return;
}
let mut clipped = vec![false; n0];
let mut i_a = rand::random::<usize>() % n0;
let mut n = n0;
let mut fails_since_advance = 0;
while n > 2 {
let mut i_b = (i_a + 1) % n0;
while clipped[i_b] {
i_b = (i_b + 1) % n0;
}
let mut i_c = (i_b + 1) % n0;
while clipped[i_c] {
i_c = (i_c + 1) % n0;
}

// println!("i_a: {}, i_b: {}, i_c: {} {:?}", i_a, i_b, i_c, clipped);
assert!(i_a != i_b);
assert!(i_b != i_c);
assert!(i_c != i_a);

// cut the ear off
if !vs[i_b].0.convex(vs[i_a].0, vs[i_c].0) || !triangle_empty(i_a, i_b, i_c) {
fails_since_advance += 1;
if fails_since_advance > n {
// TODO:
// panic!("Failed to advance");
//println!("Failed to advance {:?} {} {} {}", vs, i_a, i_b, i_c);
break;
if randomize {
i_a = rand::random::<usize>() % n0;
while clipped[i_a] {
i_a = (i_a + 1) % n0;
}
i_a = i_b;
continue;
}

indices.push(vs[i_a].1);
indices.push(vs[i_b].1);
indices.push(vs[i_c].1);
clipped[i_b] = true;
n -= 1;
fails_since_advance = 0;
i_a = rand::random::<usize>() % n0;
while clipped[i_a] {
i_a = (i_a + 1) % n0;
}
}
}
Expand Down
14 changes: 7 additions & 7 deletions src/representation/face/tesselate/min_weight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,23 +76,23 @@ where
let mut best_dist: P::S = std::f32::INFINITY.into();

for _ in 1..100 {
let mut local_indices = Vec::new();
self.ear_clipping_randomized(mesh, &mut local_indices);
let mut tmp_indices = Vec::new();
self.ear_clipping(mesh, &mut tmp_indices, false, true);

// self.shorten(mesh, &mut local_indices);

let mut dist = 0.0.into();

for i in (0..local_indices.len()).step_by(3) {
let a = mesh.vertex(local_indices[i]).vertex();
let b = mesh.vertex(local_indices[i + 1]).vertex();
let c = mesh.vertex(local_indices[i + 2]).vertex();
for i in (0..tmp_indices.len()).step_by(3) {
let a = mesh.vertex(tmp_indices[i]).vertex();
let b = mesh.vertex(tmp_indices[i + 1]).vertex();
let c = mesh.vertex(tmp_indices[i + 2]).vertex();
dist += a.distance(b) + b.distance(c) + c.distance(a);
}

if dist < best_dist {
best_dist = dist;
best_indices = local_indices;
best_indices = tmp_indices;
}
}
indices.extend(best_indices);
Expand Down
Loading

0 comments on commit 3167ffb

Please sign in to comment.