Skip to content

Commit

Permalink
fix ear clipping
Browse files Browse the repository at this point in the history
  • Loading branch information
Agapanthus committed Mar 6, 2024
1 parent 1eb706b commit 476fcea
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 12 deletions.
4 changes: 2 additions & 2 deletions benches/triangulation.rs
Expand Up @@ -51,15 +51,15 @@ fn bench_spirals(c: &mut Criterion) {
})
},
);
group.bench_with_input(
/*group.bench_with_input(
BenchmarkId::new("Delaunay", name),
&mesh,
|b, para: &MeshVec3| {
b.iter(|| {
para.tesselate(TriangulationAlgorithm::Delaunay, GenerateNormals::None);
})
},
);
);*/
}

group.finish();
Expand Down
36 changes: 29 additions & 7 deletions editor/src/main.rs
Expand Up @@ -16,7 +16,11 @@ use procedural_modelling::{
self,
bevy::{show_edges, show_faces, show_vertex_indices, text::Text3dGizmos},
},
representation::bevy::MeshVec3,
representation::{
bevy::MeshVec3,
builder::{AddVertex, CloseFace},
payload::{bevy::BevyPayload, Payload},
},
};
use std::{env, f32::consts::PI};

Expand Down Expand Up @@ -99,14 +103,32 @@ fn _make_spiral(settings: &MeshSettings) -> MeshVec3 {
}

fn make_2d_shape(_settings: &MeshSettings) -> MeshVec3 {
let mut mesh = MeshVec3::regular_star(2.0, 0.9, 10);
/*let mut mesh = MeshVec3::regular_star(2.0, 0.9, 10);
mesh.transform(&Transform::from_translation(Vec3::new(0.0, -0.99, 0.0)));
mesh*/

let mut p = [
// e1
Vec3::new(-2.0, 0.0, -2.0),
// e2
Vec3::new(2.0, 0.0, -2.0),
// e3
Vec3::new(2.0, 0.0, 2.0),
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 2.0),
Vec3::new(-1.0, 0.0, 0.0),
// e4
Vec3::new(-2.0, 0.0, 2.0),
];
p.reverse();
let mut mesh = MeshVec3::polygon(&p);
mesh.transform(&Transform::from_translation(Vec3::new(0.0, -0.99, 0.0)));
mesh
}

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 +223,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
7 changes: 7 additions & 0 deletions src/math/vector2d.rs
Expand Up @@ -12,6 +12,13 @@ pub trait Vector2D<ScalarType: Scalar>: Vector<ScalarType> {
(*self - prev).cross2d(&(next - *self)).is_positive()
}

/// True if the vertex is collinear.
fn collinear(&self, a: Self, b: Self, eps: ScalarType) -> bool {
let ab = b - a;
let ac = *self - a;
ab.cross2d(&ac).abs() <= eps
}

/// Returns the barycentric sign of a point in a triangle.
#[inline(always)]
fn barycentric_sign(a: Self, b: Self, c: Self) -> ScalarType {
Expand Down
21 changes: 19 additions & 2 deletions src/representation/face/tesselate/ear_clipping.rs
Expand Up @@ -23,6 +23,7 @@ where
) where
P::Vec: Vector3D<P::S>,
{
let eps = 0.00001.into();
debug_assert!(self.may_be_curved() || self.is_planar2(mesh));
debug_assert!(self.is_simple(mesh));

Expand Down Expand Up @@ -63,11 +64,27 @@ where
debug_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) {
if !vs[i_b].0.convex(vs[i_a].0, vs[i_c].0)
|| !triangle_empty(i_a, i_b, i_c)
|| vs[i_b].0.collinear(vs[i_a].0, vs[i_c].0, eps)
{
fails_since_advance += 1;
if fails_since_advance > n {
// TODO: don't panic; this could happen due to float inaccuracies
panic!("Failed to advance {:?} {} {} {}", vs, i_a, i_b, i_c);
println!("⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️");
println!(
"Failed to advance {} {} {}",
vs[i_a].1, vs[i_b].1, vs[i_c].1
);
println!(
"clipped: {:?}",
clipped
.iter()
.enumerate()
.filter_map(|(i, &c)| if c { Some(i) } else { None })
.collect::<Vec<_>>()
);
return;
}
i_a = i_b;
continue;
Expand Down
2 changes: 1 addition & 1 deletion src/representation/mesh/check.rs
Expand Up @@ -250,7 +250,7 @@ impl<E: IndexType, V: IndexType, F: IndexType, P: Payload> std::fmt::Display for
.collect::<Vec<_>>()
.join("\n"),
if let Err(msg) = self.check() {
format!("⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️ ERROR ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️\n{}" , msg)
format!("⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ERROR ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️\n{}" , msg)
} else {
"".to_string()
}
Expand Down
14 changes: 14 additions & 0 deletions src/representation/mesh/primitives/regular_polygon.rs
Expand Up @@ -20,6 +20,20 @@ where
Self::regular_star(radius, radius, n)
}

/// Draw a polygon from the given vertices
pub fn polygon(v: &[P::Vec]) -> Mesh<E, V, F, P> {
let mut mesh = Mesh::<E, V, F, P>::new();
assert!(v.len() >= 3);
let (v0, mut current) = mesh.add_isolated_edge(P::from_vec(v[0]), P::from_vec(v[1]));
let mut last = current;
for i in 2..v.len() {
last = current;
current = mesh.add_vertex((current, P::from_vec(v[i]))).0;
}
mesh.close_face((last, current, v0, false));
mesh
}

/// create a regular star, i.e., a regular polygon with two radii
pub fn regular_star(inner_radius: P::S, outer_radius: P::S, n: usize) -> Mesh<E, V, F, P> {
let pi2n = 2.0 * std::f32::consts::PI / (n as f32);
Expand Down

0 comments on commit 476fcea

Please sign in to comment.