mirror of
https://github.com/hannobraun/Fornjot
synced 2025-02-12 18:26:00 +00:00
Merge pull request #459 from hannobraun/mesh
Expand `Mesh` API with methods that work with triangles
This commit is contained in:
commit
9090f0f8d6
@ -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,
|
||||
|
@ -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 }
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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(¶meters)?;
|
||||
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,
|
||||
);
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user