Merge pull request #459 from hannobraun/mesh

Expand `Mesh` API with methods that work with triangles
This commit is contained in:
Hanno Braun 2022-04-12 14:20:59 +02:00 committed by GitHub
commit 9090f0f8d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 101 additions and 81 deletions

View File

@ -1,6 +1,6 @@
use std::f64::consts::FRAC_PI_2;
use fj_interop::mesh::Triangle;
use fj_interop::mesh::Mesh;
use fj_math::{Aabb, Scalar};
use nalgebra::{Point, TAffine, Transform, Translation, Vector};
use parry3d_f64::query::{Ray, RayCast as _};
@ -131,7 +131,7 @@ impl Camera {
&self,
window: &Window,
cursor: Option<PhysicalPosition<f64>>,
triangles: &[Triangle],
mesh: &Mesh<fj_math::Point<3>>,
) -> FocusPoint {
let cursor = match cursor {
Some(cursor) => cursor,
@ -147,7 +147,7 @@ impl Camera {
let mut min_t = None;
for triangle in triangles {
for triangle in mesh.triangles() {
let t = triangle.inner.to_parry().cast_local_ray(
&ray,
f64::INFINITY,

View File

@ -1,7 +1,7 @@
use bytemuck::{Pod, Zeroable};
use fj_interop::{
debug::DebugInfo,
mesh::{Index, Mesh, Triangle},
mesh::{Index, Mesh},
};
use nalgebra::{vector, Point};
@ -66,22 +66,22 @@ impl Vertices {
}
}
impl From<&Vec<Triangle>> for Vertices {
fn from(triangles: &Vec<Triangle>) -> Self {
let mut mesh = Mesh::new();
impl From<&Mesh<fj_math::Point<3>>> for Vertices {
fn from(mesh: &Mesh<fj_math::Point<3>>) -> Self {
let mut m = Mesh::new();
for triangle in triangles {
for triangle in mesh.triangles() {
let [a, b, c] = triangle.inner.points();
let normal = (b - a).cross(&(c - a)).normalize();
let color = triangle.color;
mesh.push((a, normal, color));
mesh.push((b, normal, color));
mesh.push((c, normal, color));
m.push_vertex((a, normal, color));
m.push_vertex((b, normal, color));
m.push_vertex((c, normal, color));
}
let vertices = mesh
let vertices = m
.vertices()
.map(|(vertex, normal, color)| Vertex {
position: vertex.into(),
@ -90,7 +90,7 @@ impl From<&Vec<Triangle>> for Vertices {
})
.collect();
let indices = mesh.indices().collect();
let indices = m.indices().collect();
Self { vertices, indices }
}

View File

@ -1,6 +1,7 @@
use std::time::Instant;
use fj_interop::mesh::Triangle;
use fj_interop::mesh::Mesh;
use fj_math::Point;
use winit::{
dpi::PhysicalPosition,
event::{
@ -121,9 +122,9 @@ impl Handler {
now: Instant,
camera: &mut Camera,
window: &Window,
triangles: &[Triangle],
mesh: &Mesh<Point<3>>,
) {
let focus_point = camera.focus_point(window, self.cursor, triangles);
let focus_point = camera.focus_point(window, self.cursor, mesh);
self.zoom.discard_old_events(now);
self.zoom.update_speed(now, delta_t, focus_point, camera);

View File

@ -9,10 +9,9 @@ use std::path::PathBuf;
use std::{collections::HashMap, time::Instant};
use fj_host::Model;
use fj_interop::mesh::Triangle;
use fj_interop::{debug::DebugInfo, mesh::Mesh};
use fj_kernel::algorithms::triangulate;
use fj_math::{Aabb, Scalar};
use fj_math::{Aabb, Point, Scalar};
use fj_operations::ToShape as _;
use futures::executor::block_on;
use tracing::{trace, warn};
@ -85,18 +84,10 @@ fn main() -> anyhow::Result<()> {
let shape = model.load_once(&parameters)?;
let shape = shape_processor.process(&shape);
let mut mesh_maker = Mesh::new();
for triangle in shape.triangles {
for vertex in triangle.inner.points() {
mesh_maker.push(vertex);
}
}
let vertices =
mesh_maker.vertices().map(|vertex| vertex.into()).collect();
shape.mesh.vertices().map(|vertex| vertex.into()).collect();
let indices: Vec<_> = mesh_maker.indices().collect();
let indices: Vec<_> = shape.mesh.indices().collect();
let triangles = indices
.chunks(3)
.map(|triangle| {
@ -187,7 +178,7 @@ fn main() -> anyhow::Result<()> {
let focus_point = camera.focus_point(
&window,
input_handler.cursor(),
&shape.triangles,
&shape.mesh,
);
input_handler.handle_mouse_input(
@ -213,7 +204,7 @@ fn main() -> anyhow::Result<()> {
now,
camera,
&window,
&shape.triangles,
&shape.mesh,
);
}
@ -292,17 +283,15 @@ impl ShapeProcessor {
};
let mut debug_info = DebugInfo::new();
let mut triangles = Vec::new();
triangulate(
let mesh = triangulate(
shape.to_shape(tolerance, &mut debug_info),
tolerance,
&mut triangles,
&mut debug_info,
);
ProcessedShape {
aabb,
triangles,
mesh,
debug_info,
}
}
@ -310,14 +299,14 @@ impl ShapeProcessor {
struct ProcessedShape {
aabb: Aabb<3>,
triangles: Vec<Triangle>,
mesh: Mesh<Point<3>>,
debug_info: DebugInfo,
}
impl ProcessedShape {
fn update_geometry(&self, renderer: &mut Renderer) {
renderer.update_geometry(
(&self.triangles).into(),
(&self.mesh).into(),
(&self.debug_info).into(),
self.aabb,
);

View File

@ -2,12 +2,15 @@
use std::{collections::HashMap, hash::Hash};
use fj_math::Point;
/// A triangle mesh
pub struct Mesh<V> {
vertices: Vec<V>,
indices: Vec<Index>,
indices_by_vertex: HashMap<V, Index>,
triangles: Vec<Triangle>,
}
impl<V> Mesh<V>
@ -20,7 +23,7 @@ where
}
/// Add a vertex to the mesh
pub fn push(&mut self, vertex: V) {
pub fn push_vertex(&mut self, vertex: V) {
let index =
*self.indices_by_vertex.entry(vertex).or_insert_with(|| {
let index = self.vertices.len();
@ -31,6 +34,25 @@ where
self.indices.push(index);
}
/// Determine whether the mesh contains the provided triangle
///
/// Returns true, if a triangle with any combination of the points of the
/// provided triangle is part of the mesh.
pub fn contains_triangle(
&self,
triangle: impl Into<fj_math::Triangle<3>>,
) -> bool {
let triangle = triangle.into().normalize();
for t in &self.triangles {
if triangle == t.inner.normalize() {
return true;
}
}
false
}
/// Access the vertices of the mesh
pub fn vertices(&self) -> impl Iterator<Item = V> + '_ {
self.vertices.iter().copied()
@ -40,6 +62,28 @@ where
pub fn indices(&self) -> impl Iterator<Item = Index> + '_ {
self.indices.iter().copied()
}
/// Access the triangles of the mesh
pub fn triangles(&self) -> impl Iterator<Item = Triangle> + '_ {
self.triangles.iter().copied()
}
}
impl Mesh<Point<3>> {
/// Add a triangle to the mesh
pub fn push_triangle(
&mut self,
triangle: impl Into<fj_math::Triangle<3>>,
color: Color,
) {
let triangle = triangle.into();
for point in triangle.points() {
self.push_vertex(point);
}
self.triangles.push(Triangle::new(triangle, color));
}
}
// This needs to be a manual implementation. Deriving `Default` would require
@ -50,6 +94,7 @@ impl<V> Default for Mesh<V> {
vertices: Default::default(),
indices: Default::default(),
indices_by_vertex: Default::default(),
triangles: Default::default(),
}
}
}

View File

@ -2,8 +2,8 @@ mod delaunay;
mod polygon;
mod ray;
use fj_interop::{debug::DebugInfo, mesh::Triangle};
use fj_math::Scalar;
use fj_interop::{debug::DebugInfo, mesh::Mesh};
use fj_math::{Point, Scalar};
use crate::{shape::Shape, topology::Face};
@ -15,9 +15,10 @@ use super::FaceApprox;
pub fn triangulate(
mut shape: Shape,
tolerance: Scalar,
out: &mut Vec<Triangle>,
debug_info: &mut DebugInfo,
) {
) -> Mesh<Point<3>> {
let mut mesh = Mesh::new();
for face in shape.topology().faces() {
let face = face.get();
match &face {
@ -61,20 +62,26 @@ pub fn triangulate(
)
});
out.extend(triangles.into_iter().map(|triangle| {
for triangle in triangles {
let points = triangle.map(|point| point.canonical());
Triangle::new(points, *color)
}));
mesh.push_triangle(points, *color);
}
}
Face::Triangles(triangles) => {
for triangle in triangles {
mesh.push_triangle(triangle.inner, triangle.color);
}
}
Face::Triangles(triangles) => out.extend(triangles),
}
}
mesh
}
#[cfg(test)]
mod tests {
use fj_interop::{debug::DebugInfo, mesh::Triangle};
use fj_math::Scalar;
use fj_interop::{debug::DebugInfo, mesh::Mesh};
use fj_math::{Point, Scalar};
use crate::{geometry::Surface, shape::Shape, topology::Face};
@ -92,10 +99,10 @@ mod tests {
.build()?;
let triangles = triangulate(shape);
assert!(triangles.contains([a, b, d]));
assert!(triangles.contains([b, c, d]));
assert!(!triangles.contains([a, b, c]));
assert!(!triangles.contains([a, c, d]));
assert!(triangles.contains_triangle([a, b, d]));
assert!(triangles.contains_triangle([b, c, d]));
assert!(!triangles.contains_triangle([a, b, c]));
assert!(!triangles.contains_triangle([a, c, d]));
Ok(())
}
@ -123,44 +130,22 @@ mod tests {
// Should contain some triangles from the polygon. Don't need to test
// them all.
assert!(triangles.contains([a, e, h]));
assert!(triangles.contains([a, d, h]));
assert!(triangles.contains_triangle([a, e, h]));
assert!(triangles.contains_triangle([a, d, h]));
// Shouldn't contain any possible triangle from the hole.
assert!(!triangles.contains([e, f, g]));
assert!(!triangles.contains([e, g, h]));
assert!(!triangles.contains([e, f, h]));
assert!(!triangles.contains([f, g, h]));
assert!(!triangles.contains_triangle([e, f, g]));
assert!(!triangles.contains_triangle([e, g, h]));
assert!(!triangles.contains_triangle([e, f, h]));
assert!(!triangles.contains_triangle([f, g, h]));
Ok(())
}
fn triangulate(shape: Shape) -> Triangles {
fn triangulate(shape: Shape) -> Mesh<Point<3>> {
let tolerance = Scalar::ONE;
let mut triangles = Vec::new();
let mut debug_info = DebugInfo::new();
super::triangulate(shape, tolerance, &mut triangles, &mut debug_info);
for triangle in &mut triangles {
*triangle = Triangle {
inner: triangle.inner.normalize(),
..*triangle
};
}
Triangles(triangles)
}
#[derive(Debug)]
struct Triangles(Vec<Triangle>);
impl Triangles {
fn contains(&self, triangle: impl Into<fj_math::Triangle<3>>) -> bool {
let triangle =
Triangle::new(triangle.into().normalize(), [255, 0, 0, 255]);
self.0.contains(&triangle)
}
super::triangulate(shape, tolerance, &mut debug_info)
}
}