Use proper ear cutting
This commit is contained in:
parent
9e9254b04c
commit
7c8a9f1b58
2 changed files with 103 additions and 70 deletions
|
@ -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"
|
||||
|
|
172
src/polygon.rs
172
src/polygon.rs
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue