Inline method call

This commit is contained in:
Hanno Braun 2022-03-21 17:33:53 +01:00
parent b483a5dd4a
commit 6a0417bb2d
2 changed files with 150 additions and 161 deletions

View File

@ -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),
}
}
}

View File

@ -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 {