Use proper ear cutting

This commit is contained in:
hodasemi 2023-05-15 09:49:54 +02:00
parent 9e9254b04c
commit 7c8a9f1b58
2 changed files with 103 additions and 70 deletions

View file

@ -9,3 +9,4 @@ edition = "2021"
bevy = "0.10.1"
bevy_egui = "0.20.3"
bevy-inspector-egui = "0.18.3"
earcutr = "0.4.2"

View file

@ -6,6 +6,8 @@ use bevy::{
sprite::MaterialMesh2dBundle,
};
use earcutr::earcut;
use crate::global_state::GlobalState;
#[derive(Default, Debug, PartialEq)]
@ -145,8 +147,6 @@ impl Polygon {
}
}
self.order_points();
// create triangle mesh
let triangle_mesh = self.create_triangulated_mesh();
@ -161,48 +161,10 @@ impl Polygon {
.id();
// create 3d object
let vertices: Vec<Vec3> = self
.points
.iter()
.map(|p| vec![p.extend(0.0), p.extend(global_state.extrusion_height)])
.flatten()
.collect();
let indices = Indices::U32({
let mut v = Vec::new();
for i in 0..self.points.len() {
let index = (i as u32) * 2;
// create quads from 4 adjacent points
v.push(index);
v.push((index + 2) % vertices.len() as u32);
v.push(index + 1);
v.push(index + 1);
v.push((index + 2) % vertices.len() as u32);
v.push((index + 3) % vertices.len() as u32);
}
// TODO: proper ear cutting algo
for i in 2..self.points.len() as u32 {
let index = (i as u32) * 2 + 1;
v.push(1);
v.push(index - 2);
v.push(index);
}
v
});
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
mesh.set_indices(Some(indices));
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, vertices);
let mesh_id = commands
.spawn((
MaterialMeshBundle {
mesh: meshes.add(mesh).into(),
mesh: meshes.add(self.create_3d_mesh(global_state)).into(),
transform: Transform::default(),
material: standard_materials.add(StandardMaterial::from(Color::BLACK)),
..default()
@ -274,23 +236,6 @@ impl Polygon {
}
}
fn order_points(&mut self) {
let n = Vec3::Z;
let v1 = (self.points[0] - self.points[1]).normalize().extend(0.0);
let v2 = (self.points[1] - self.points[2]).normalize().extend(0.0);
let c1 = v1.cross(n);
let d = c1.dot(v2);
// dot product is bigger than 0 if normal and connection line are facing in the same direction
// reverse the order of points, thus the face of the 3d object is directed to the outside
if d >= 0.0 {
self.points = self.points.iter().cloned().rev().collect();
}
}
fn check_all_for_proximity(&self, point: Vec2) -> bool {
self.points
.iter()
@ -306,18 +251,22 @@ impl Polygon {
fn create_triangulated_mesh(&self) -> Mesh {
let vertices: Vec<_> = self.points.iter().map(|p| p.extend(0.0)).collect();
// TODO: proper ear cutting algo
let indices = Indices::U32({
let mut v = Vec::new();
for i in 2..self.points.len() as u32 {
v.push(0);
v.push(i - 1);
v.push(i);
}
v
});
let indices = Indices::U32(
earcut(
self.points
.iter()
.map(|p| vec![p.x, p.y])
.flatten()
.collect::<Vec<f32>>()
.as_slice(),
&[],
2,
)
.unwrap()
.into_iter()
.map(|i| i as u32)
.collect(),
);
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
mesh.set_indices(Some(indices));
@ -326,6 +275,89 @@ impl Polygon {
mesh
}
fn create_3d_mesh(&self, global_state: &GlobalState) -> Mesh {
let mut outer_faces = {
let mean =
(self.points.iter().cloned().sum::<Vec2>() / self.points.len() as f32).extend(0.0);
let v1: Vec<Vec3> = self
.points
.iter()
.map(|p| vec![p.extend(0.0), p.extend(global_state.extrusion_height)])
.flatten()
.collect();
let mut v = Vec::new();
for i in 0..self.points.len() {
let index = (i) * 2;
// create quads from 4 adjacent points
let mut p = vec![
index,
(index + 2) % v1.len(),
index + 1,
index + 1,
(index + 2) % v1.len(),
(index + 3) % v1.len(),
];
// check if the normal of the face is facing towards the center of the polygon
// if so, reverse the order that the normal is facing outwards
let n = (v1[p[0]] - v1[p[1]]).cross(v1[p[1]] - v1[p[2]]);
if 0.0 > n.dot(v1[p[0]] - mean) {
p.reverse();
}
v.extend(p);
}
let mut vertices = Vec::new();
for i in v {
vertices.push(v1[i]);
}
vertices
};
let top = {
let top_vertices: Vec<Vec3> = self
.points
.iter()
.map(|p| p.extend(global_state.extrusion_height))
.collect();
let indices = earcut(
self.points
.iter()
.map(|v| [v.x, v.y])
.flatten()
.collect::<Vec<f32>>()
.as_slice(),
&[],
2,
)
.unwrap();
let mut vertices = Vec::new();
for i in indices.into_iter() {
vertices.push(top_vertices[i]);
}
vertices
};
outer_faces.extend(top);
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, outer_faces);
mesh
}
fn create_line_mesh(start: Vec2, end: Vec2) -> Mesh {
let d = start.distance(end);