mirror of
https://github.com/hannobraun/Fornjot
synced 2025-02-25 16:45:52 +00:00
Inline method call
This commit is contained in:
parent
b483a5dd4a
commit
6a0417bb2d
@ -1,9 +1,17 @@
|
||||
use fj_debug::DebugInfo;
|
||||
use fj_math::{Scalar, Triangle};
|
||||
use parry2d_f64::utils::point_in_triangle::{corner_direction, Orientation};
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use fj_debug::{DebugInfo, TriangleEdgeCheck};
|
||||
use fj_math::{Aabb, Scalar, Segment, Triangle};
|
||||
use parry2d_f64::{
|
||||
query::{Ray as Ray2, RayCast as _},
|
||||
utils::point_in_triangle::{corner_direction, Orientation},
|
||||
};
|
||||
use parry3d_f64::query::Ray as Ray3;
|
||||
use spade::HasPosition;
|
||||
|
||||
use crate::{geometry, shape::Shape};
|
||||
use crate::{geometry, shape::Shape, topology::Face};
|
||||
|
||||
use super::Approximation;
|
||||
|
||||
/// Triangulate a shape
|
||||
pub fn triangulate(
|
||||
@ -13,7 +21,141 @@ pub fn triangulate(
|
||||
debug_info: &mut DebugInfo,
|
||||
) {
|
||||
for face in shape.topology().faces() {
|
||||
face.get().triangles(tolerance, out, debug_info);
|
||||
let face = face.get();
|
||||
match &*face {
|
||||
Face::Face { surface, color, .. } => {
|
||||
let surface = surface.get();
|
||||
let approx = Approximation::for_face(&face, tolerance);
|
||||
|
||||
let points: Vec<_> = approx
|
||||
.points
|
||||
.into_iter()
|
||||
.map(|vertex| {
|
||||
// Can't panic, unless the approximation wrongfully
|
||||
// generates points that are not in the surface.
|
||||
surface.point_model_to_surface(vertex)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let segments: Vec<_> = approx
|
||||
.segments
|
||||
.into_iter()
|
||||
.map(|segment| {
|
||||
let [a, b] = segment.points();
|
||||
|
||||
// Can't panic, unless the approximation wrongfully
|
||||
// generates points that are not in the surface.
|
||||
let a = surface.point_model_to_surface(a);
|
||||
let b = surface.point_model_to_surface(b);
|
||||
|
||||
[a, b]
|
||||
})
|
||||
.collect();
|
||||
|
||||
// We're also going to need a point outside of the polygon, for
|
||||
// the point-in-polygon tests.
|
||||
let aabb = Aabb::<2>::from_points(
|
||||
points.iter().map(|vertex| vertex.native()),
|
||||
);
|
||||
let outside = aabb.max * 2.;
|
||||
|
||||
let mut triangles = delaunay(points);
|
||||
let face_as_polygon = segments;
|
||||
|
||||
triangles.retain(|t| {
|
||||
for segment in [t[0], t[1], t[2], t[0]].windows(2) {
|
||||
// This can't panic, as we passed `2` to `windows`. It
|
||||
// can be cleaned up a bit, once `array_windows` is
|
||||
// stable.
|
||||
let segment = [segment[0], segment[1]];
|
||||
let inverted_segment = [segment[1], segment[0]];
|
||||
|
||||
// If the segment is an edge of the face, we don't need
|
||||
// to take a closer look.
|
||||
if face_as_polygon.contains(&segment) {
|
||||
continue;
|
||||
}
|
||||
if face_as_polygon.contains(&inverted_segment) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// To determine if the edge is within the polygon, we
|
||||
// determine if its center point is in the polygon.
|
||||
let center = segment[0]
|
||||
+ (segment[1] - segment[0]) / Scalar::TWO;
|
||||
|
||||
let origin = center;
|
||||
let dir = outside - center;
|
||||
let ray = Ray2 {
|
||||
origin: origin.to_na(),
|
||||
dir: dir.to_na(),
|
||||
};
|
||||
|
||||
let mut check = TriangleEdgeCheck::new(Ray3 {
|
||||
origin: surface
|
||||
.point_surface_to_model(&origin)
|
||||
.to_na(),
|
||||
dir: surface.vector_surface_to_model(&dir).to_na(),
|
||||
});
|
||||
|
||||
// We need to keep track of where our ray hits the
|
||||
// edges. Otherwise, if the ray hits a vertex, we might
|
||||
// count that hit twice, as every vertex is attached to
|
||||
// two edges.
|
||||
let mut hits = BTreeSet::new();
|
||||
|
||||
// Use ray-casting to determine if `center` is within
|
||||
// the face-polygon.
|
||||
for edge in &face_as_polygon {
|
||||
// Please note that we if we get to this point, then
|
||||
// the point is not on a polygon edge, due to the
|
||||
// check above. We don't need to handle any edge
|
||||
// cases that would arise from that case.
|
||||
|
||||
let edge =
|
||||
Segment::from(edge.map(|point| point.native()));
|
||||
|
||||
let intersection = edge
|
||||
.to_parry()
|
||||
.cast_local_ray(&ray, f64::INFINITY, true)
|
||||
.map(Scalar::from_f64);
|
||||
|
||||
if let Some(t) = intersection {
|
||||
// Due to slight inaccuracies, we might get
|
||||
// different values for the same intersections.
|
||||
// Let's round `t` before using it.
|
||||
let eps = 1_000_000.0;
|
||||
let t = (t * eps).round() / eps;
|
||||
|
||||
if hits.insert(t) {
|
||||
check.hits.push(t.into_f64());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug_info.triangle_edge_checks.push(check);
|
||||
|
||||
if hits.len() % 2 == 0 {
|
||||
// The segment is outside of the face. This means we
|
||||
// can throw away the whole triangle.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't throw away the triangle up till now, this
|
||||
// means all its edges are within the face.
|
||||
true
|
||||
});
|
||||
|
||||
out.extend(triangles.into_iter().map(|triangle| {
|
||||
let [a, b, c] = triangle.map(|point| point.canonical());
|
||||
let mut t = Triangle::from([a, b, c]);
|
||||
t.set_color(*color);
|
||||
t
|
||||
}));
|
||||
}
|
||||
Face::Triangles(triangles) => out.extend(triangles),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,8 @@
|
||||
use std::{
|
||||
collections::BTreeSet,
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use fj_debug::{DebugInfo, TriangleEdgeCheck};
|
||||
use fj_math::{Aabb, Scalar, Segment, Triangle};
|
||||
use parry2d_f64::query::{Ray as Ray2, RayCast as _};
|
||||
use parry3d_f64::query::Ray as Ray3;
|
||||
use fj_math::Triangle;
|
||||
|
||||
use crate::{
|
||||
algorithms::{delaunay, Approximation},
|
||||
geometry::Surface,
|
||||
shape::Handle,
|
||||
};
|
||||
use crate::{geometry::Surface, shape::Handle};
|
||||
|
||||
use super::edges::Cycle;
|
||||
|
||||
@ -89,149 +79,6 @@ impl Face {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Triangulate the face
|
||||
pub fn triangles(
|
||||
&self,
|
||||
tolerance: Scalar,
|
||||
out: &mut Vec<Triangle<3>>,
|
||||
debug_info: &mut DebugInfo,
|
||||
) {
|
||||
match self {
|
||||
Self::Face { surface, color, .. } => {
|
||||
let surface = surface.get();
|
||||
let approx = Approximation::for_face(self, tolerance);
|
||||
|
||||
let points: Vec<_> = approx
|
||||
.points
|
||||
.into_iter()
|
||||
.map(|vertex| {
|
||||
// Can't panic, unless the approximation wrongfully
|
||||
// generates points that are not in the surface.
|
||||
surface.point_model_to_surface(vertex)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let segments: Vec<_> = approx
|
||||
.segments
|
||||
.into_iter()
|
||||
.map(|segment| {
|
||||
let [a, b] = segment.points();
|
||||
|
||||
// Can't panic, unless the approximation wrongfully
|
||||
// generates points that are not in the surface.
|
||||
let a = surface.point_model_to_surface(a);
|
||||
let b = surface.point_model_to_surface(b);
|
||||
|
||||
[a, b]
|
||||
})
|
||||
.collect();
|
||||
|
||||
// We're also going to need a point outside of the polygon, for
|
||||
// the point-in-polygon tests.
|
||||
let aabb = Aabb::<2>::from_points(
|
||||
points.iter().map(|vertex| vertex.native()),
|
||||
);
|
||||
let outside = aabb.max * 2.;
|
||||
|
||||
let mut triangles = delaunay(points);
|
||||
let face_as_polygon = segments;
|
||||
|
||||
triangles.retain(|t| {
|
||||
for segment in [t[0], t[1], t[2], t[0]].windows(2) {
|
||||
// This can't panic, as we passed `2` to `windows`. It
|
||||
// can be cleaned up a bit, once `array_windows` is
|
||||
// stable.
|
||||
let segment = [segment[0], segment[1]];
|
||||
let inverted_segment = [segment[1], segment[0]];
|
||||
|
||||
// If the segment is an edge of the face, we don't need
|
||||
// to take a closer look.
|
||||
if face_as_polygon.contains(&segment) {
|
||||
continue;
|
||||
}
|
||||
if face_as_polygon.contains(&inverted_segment) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// To determine if the edge is within the polygon, we
|
||||
// determine if its center point is in the polygon.
|
||||
let center = segment[0]
|
||||
+ (segment[1] - segment[0]) / Scalar::TWO;
|
||||
|
||||
let origin = center;
|
||||
let dir = outside - center;
|
||||
let ray = Ray2 {
|
||||
origin: origin.to_na(),
|
||||
dir: dir.to_na(),
|
||||
};
|
||||
|
||||
let mut check = TriangleEdgeCheck::new(Ray3 {
|
||||
origin: surface
|
||||
.point_surface_to_model(&origin)
|
||||
.to_na(),
|
||||
dir: surface.vector_surface_to_model(&dir).to_na(),
|
||||
});
|
||||
|
||||
// We need to keep track of where our ray hits the
|
||||
// edges. Otherwise, if the ray hits a vertex, we might
|
||||
// count that hit twice, as every vertex is attached to
|
||||
// two edges.
|
||||
let mut hits = BTreeSet::new();
|
||||
|
||||
// Use ray-casting to determine if `center` is within
|
||||
// the face-polygon.
|
||||
for edge in &face_as_polygon {
|
||||
// Please note that we if we get to this point, then
|
||||
// the point is not on a polygon edge, due to the
|
||||
// check above. We don't need to handle any edge
|
||||
// cases that would arise from that case.
|
||||
|
||||
let edge =
|
||||
Segment::from(edge.map(|point| point.native()));
|
||||
|
||||
let intersection = edge
|
||||
.to_parry()
|
||||
.cast_local_ray(&ray, f64::INFINITY, true)
|
||||
.map(Scalar::from_f64);
|
||||
|
||||
if let Some(t) = intersection {
|
||||
// Due to slight inaccuracies, we might get
|
||||
// different values for the same intersections.
|
||||
// Let's round `t` before using it.
|
||||
let eps = 1_000_000.0;
|
||||
let t = (t * eps).round() / eps;
|
||||
|
||||
if hits.insert(t) {
|
||||
check.hits.push(t.into_f64());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug_info.triangle_edge_checks.push(check);
|
||||
|
||||
if hits.len() % 2 == 0 {
|
||||
// The segment is outside of the face. This means we
|
||||
// can throw away the whole triangle.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't throw away the triangle up till now, this
|
||||
// means all its edges are within the face.
|
||||
true
|
||||
});
|
||||
|
||||
out.extend(triangles.into_iter().map(|triangle| {
|
||||
let [a, b, c] = triangle.map(|point| point.canonical());
|
||||
let mut t = Triangle::from([a, b, c]);
|
||||
t.set_color(*color);
|
||||
t
|
||||
}));
|
||||
}
|
||||
Self::Triangles(triangles) => out.extend(triangles),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Face {
|
||||
|
Loading…
Reference in New Issue
Block a user