Merge pull request #2417 from hannobraun/geom

Replace all reads of half-edge geometry with reads of vertex geometry
This commit is contained in:
Hanno Braun 2024-07-09 22:05:01 +02:00 committed by GitHub
commit 7c7bfe5c0b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 240 additions and 65 deletions

View File

@ -5,7 +5,7 @@
use fj_math::Segment; use fj_math::Segment;
use crate::{ use crate::{
geometry::Geometry, geometry::{CurveBoundary, Geometry},
storage::Handle, storage::Handle,
topology::{Cycle, Surface}, topology::{Cycle, Surface},
}; };
@ -28,9 +28,24 @@ pub fn approx_cycle(
let half_edges = cycle let half_edges = cycle
.half_edges() .half_edges()
.iter() .pairs()
.map(|half_edge| { .map(|(half_edge, next_half_edge)| {
let boundary = geometry.of_half_edge(half_edge).boundary; let boundary = CurveBoundary {
inner: [
geometry
.of_vertex(half_edge.start_vertex())
.unwrap()
.local_on(half_edge.curve())
.unwrap()
.position,
geometry
.of_vertex(next_half_edge.start_vertex())
.unwrap()
.local_on(half_edge.curve())
.unwrap()
.position,
],
};
let [start_position_curve, _] = boundary.inner; let [start_position_curve, _] = boundary.inner;
let start = approx_vertex( let start = approx_vertex(

View File

@ -12,8 +12,8 @@ impl super::BoundingVolume<2> for (&Cycle, &Handle<Surface>) {
let mut aabb: Option<Aabb<2>> = None; let mut aabb: Option<Aabb<2>> = None;
for half_edge in cycle.half_edges() { for (half_edge, half_edge_next) in cycle.half_edges().pairs() {
let new_aabb = (half_edge, surface) let new_aabb = (half_edge, half_edge_next.start_vertex(), surface)
.aabb(geometry) .aabb(geometry)
.expect("`HalfEdge` can always compute AABB"); .expect("`HalfEdge` can always compute AABB");
aabb = Some(aabb.map_or(new_aabb, |aabb| aabb.merged(&new_aabb))); aabb = Some(aabb.map_or(new_aabb, |aabb| aabb.merged(&new_aabb)));

View File

@ -3,14 +3,15 @@ use fj_math::{Aabb, Vector};
use crate::{ use crate::{
geometry::{Geometry, SurfacePath}, geometry::{Geometry, SurfacePath},
storage::Handle, storage::Handle,
topology::{HalfEdge, Surface}, topology::{HalfEdge, Surface, Vertex},
}; };
impl super::BoundingVolume<2> for (&Handle<HalfEdge>, &Handle<Surface>) { impl super::BoundingVolume<2>
for (&Handle<HalfEdge>, &Handle<Vertex>, &Handle<Surface>)
{
fn aabb(self, geometry: &Geometry) -> Option<Aabb<2>> { fn aabb(self, geometry: &Geometry) -> Option<Aabb<2>> {
let (half_edge, surface) = self; let (half_edge, end_vertex, surface) = self;
let half_edge_geom = geometry.of_half_edge(half_edge);
let path = geometry let path = geometry
.of_curve(half_edge.curve()) .of_curve(half_edge.curve())
.unwrap() .unwrap()
@ -32,9 +33,17 @@ impl super::BoundingVolume<2> for (&Handle<HalfEdge>, &Handle<Surface>) {
}) })
} }
SurfacePath::Line(_) => { SurfacePath::Line(_) => {
let points = half_edge_geom.boundary.inner.map(|point_curve| { let points =
path.point_from_path_coords(point_curve) [half_edge.start_vertex(), end_vertex].map(|vertex| {
}); let point_curve = geometry
.of_vertex(vertex)
.unwrap()
.local_on(half_edge.curve())
.unwrap()
.position;
path.point_from_path_coords(point_curve)
});
Some(Aabb::<2>::from_points(points)) Some(Aabb::<2>::from_points(points))
} }

View File

@ -104,29 +104,43 @@ impl SplitFace for Shell {
// Build the edge that's going to divide the new faces. // Build the edge that's going to divide the new faces.
let dividing_half_edge_a_to_d = { let dividing_half_edge_a_to_d = {
let start = core
.layers
.geometry
.of_curve(b.curve())
.unwrap()
.local_on(face.surface())
.unwrap()
.path
.point_from_path_coords(
core.layers
.geometry
.of_vertex(b.start_vertex())
.unwrap()
.local_on(b.curve())
.unwrap()
.position,
);
let end = core
.layers
.geometry
.of_curve(d.curve())
.unwrap()
.local_on(face.surface())
.unwrap()
.path
.point_from_path_coords(
core.layers
.geometry
.of_vertex(d.start_vertex())
.unwrap()
.local_on(d.curve())
.unwrap()
.position,
);
let (half_edge, boundary) = HalfEdge::line_segment( let (half_edge, boundary) = HalfEdge::line_segment(
[ [start, end],
core.layers.geometry.of_half_edge(&b).start_position(
&core
.layers
.geometry
.of_curve(b.curve())
.unwrap()
.local_on(face.surface())
.unwrap()
.path,
),
core.layers.geometry.of_half_edge(&d).start_position(
&core
.layers
.geometry
.of_curve(d.curve())
.unwrap()
.local_on(face.surface())
.unwrap()
.path,
),
],
face.surface().clone(), face.surface().clone(),
core, core,
); );

View File

@ -46,7 +46,27 @@ impl SplitHalfEdge for Cycle {
let point = point.into(); let point = point.into();
let geometry = *core.layers.geometry.of_half_edge(half_edge); let geometry = *core.layers.geometry.of_half_edge(half_edge);
let [start, end] = geometry.boundary.inner; let [start, end] = [
core.layers
.geometry
.of_vertex(half_edge.start_vertex())
.unwrap()
.local_on(half_edge.curve())
.unwrap()
.position,
core.layers
.geometry
.of_vertex(
self.half_edges()
.after(half_edge)
.expect("Expected half-edge to be in cycle")
.start_vertex(),
)
.unwrap()
.local_on(half_edge.curve())
.unwrap()
.position,
];
let a = HalfEdge::new( let a = HalfEdge::new(
half_edge.curve().clone(), half_edge.curve().clone(),

View File

@ -59,7 +59,22 @@ impl SweepHalfEdge for Handle<HalfEdge> {
) -> SweptHalfEdge { ) -> SweptHalfEdge {
let path = path.into(); let path = path.into();
let half_edge_geom = *core.layers.geometry.of_half_edge(self); let boundary = [
core.layers
.geometry
.of_vertex(self.start_vertex())
.unwrap()
.local_on(self.curve())
.unwrap()
.position,
core.layers
.geometry
.of_vertex(&end_vertex)
.unwrap()
.local_on(self.curve())
.unwrap()
.position,
];
let curve_geom = core let curve_geom = core
.layers .layers
.geometry .geometry
@ -94,7 +109,7 @@ impl SweepHalfEdge for Handle<HalfEdge> {
// Let's figure out the surface coordinates of the edge vertices. // Let's figure out the surface coordinates of the edge vertices.
let surface_points = { let surface_points = {
let [a, b] = half_edge_geom.boundary.inner; let [a, b] = boundary;
[ [
[a.t, Scalar::ZERO], [a.t, Scalar::ZERO],
@ -112,7 +127,7 @@ impl SweepHalfEdge for Handle<HalfEdge> {
// Now, the boundaries of each edge. // Now, the boundaries of each edge.
let boundaries = { let boundaries = {
let [a, b] = half_edge_geom.boundary.inner; let [a, b] = boundary;
let [c, d] = [0., 1.].map(|coord| Point::from([coord])); let [c, d] = [0., 1.].map(|coord| Point::from([coord]));
[[a, b], [c, d], [b, a], [d, c]] [[a, b], [c, d], [b, a], [d, c]]

View File

@ -46,7 +46,6 @@ impl Cycle {
.next() .next()
.expect("Invalid cycle: expected at least one edge"); .expect("Invalid cycle: expected at least one edge");
let half_edge_geom = geometry.of_half_edge(first);
let curve_geom = geometry let curve_geom = geometry
.of_curve(first.curve()) .of_curve(first.curve())
.unwrap() .unwrap()
@ -54,7 +53,29 @@ impl Cycle {
.unwrap() .unwrap()
.clone(); .clone();
let [a, b] = half_edge_geom.boundary.inner; let [a, b] = [
curve_geom.path.point_from_path_coords(
geometry
.of_vertex(first.start_vertex())
.unwrap()
.local_on(first.curve())
.unwrap()
.position,
),
curve_geom.path.point_from_path_coords(
geometry
.of_vertex(
self.half_edges()
.after(first)
.expect("Just got half-edge from this cycle")
.start_vertex(),
)
.unwrap()
.local_on(first.curve())
.unwrap()
.position,
),
];
let edge_direction_positive = a < b; let edge_direction_positive = a < b;
let circle = match curve_geom.path { let circle = match curve_geom.path {
@ -80,14 +101,20 @@ impl Cycle {
for (a, b) in self.half_edges().pairs() { for (a, b) in self.half_edges().pairs() {
let [a, b] = [a, b].map(|half_edge| { let [a, b] = [a, b].map(|half_edge| {
geometry.of_half_edge(half_edge).start_position( geometry
&geometry .of_curve(half_edge.curve())
.of_curve(half_edge.curve()) .unwrap()
.unwrap() .local_on(surface)
.local_on(surface) .unwrap()
.unwrap() .path
.path, .point_from_path_coords(
) geometry
.of_vertex(half_edge.start_vertex())
.unwrap()
.local_on(half_edge.curve())
.unwrap()
.position,
)
}); });
sum += (b.u - a.u) * (b.v + a.v); sum += (b.u - a.u) * (b.v + a.v);

View File

@ -117,9 +117,14 @@ impl SolidValidationError {
Some(( Some((
geometry.of_surface(s).point_from_surface_coords( geometry.of_surface(s).point_from_surface_coords(
geometry local_curve_geometry.path.point_from_path_coords(
.of_half_edge(&h) geometry
.start_position(&local_curve_geometry.path), .of_vertex(h.start_vertex())
.unwrap()
.local_on(h.curve())
.unwrap()
.position,
),
), ),
h.start_vertex().clone(), h.start_vertex().clone(),
)) ))

View File

@ -5,7 +5,8 @@ use fj_math::{Point, Scalar};
use crate::{ use crate::{
geometry::{CurveBoundary, Geometry}, geometry::{CurveBoundary, Geometry},
queries::{ queries::{
AllHalfEdgesWithSurface, BoundingVerticesOfHalfEdge, SiblingOfHalfEdge, AllHalfEdgesWithSurface, BoundingVerticesOfHalfEdge, CycleOfHalfEdge,
SiblingOfHalfEdge,
}, },
storage::Handle, storage::Handle,
topology::{Curve, HalfEdge, Shell, Surface, Vertex}, topology::{Curve, HalfEdge, Shell, Surface, Vertex},
@ -109,8 +110,22 @@ impl ValidationCheck<Shell> for CoincidentHalfEdgesAreNotSiblings {
let Some(mut distances) = distances( let Some(mut distances) = distances(
half_edge_a.clone(), half_edge_a.clone(),
object
.find_cycle_of_half_edge(half_edge_a)
.unwrap()
.half_edges()
.after(half_edge_a)
.unwrap()
.start_vertex(),
surface_a, surface_a,
half_edge_b.clone(), half_edge_b.clone(),
object
.find_cycle_of_half_edge(half_edge_b)
.unwrap()
.half_edges()
.after(half_edge_b)
.unwrap()
.start_vertex(),
surface_b, surface_b,
geometry, geometry,
) else { ) else {
@ -152,25 +167,39 @@ impl ValidationCheck<Shell> for CoincidentHalfEdgesAreNotSiblings {
/// Returns an [`Iterator`] of the distance at each sample. /// Returns an [`Iterator`] of the distance at each sample.
fn distances( fn distances(
half_edge_a: Handle<HalfEdge>, half_edge_a: Handle<HalfEdge>,
end_vertex_a: &Handle<Vertex>,
surface_a: &Handle<Surface>, surface_a: &Handle<Surface>,
half_edge_b: Handle<HalfEdge>, half_edge_b: Handle<HalfEdge>,
end_vertex_b: &Handle<Vertex>,
surface_b: &Handle<Surface>, surface_b: &Handle<Surface>,
geometry: &Geometry, geometry: &Geometry,
) -> Option<impl Iterator<Item = Scalar>> { ) -> Option<impl Iterator<Item = Scalar>> {
fn sample( fn sample(
percent: f64, percent: f64,
half_edge: &Handle<HalfEdge>, half_edge: &Handle<HalfEdge>,
end_vertex: &Handle<Vertex>,
surface: &Handle<Surface>, surface: &Handle<Surface>,
geometry: &Geometry, geometry: &Geometry,
) -> Option<Point<3>> { ) -> Option<Point<3>> {
let [start, end] = geometry.of_half_edge(half_edge).boundary.inner; let [start, end] = [
geometry
.of_vertex(half_edge.start_vertex())
.unwrap()
.local_on(half_edge.curve())
.unwrap()
.position,
geometry
.of_vertex(end_vertex)
.unwrap()
.local_on(half_edge.curve())
.unwrap()
.position,
];
let path_coords = start + (end - start) * percent; let path_coords = start + (end - start) * percent;
// let path = geometry.of_half_edge(half_edge).path;
let path = geometry let path = geometry
.of_curve(half_edge.curve())? .of_curve(half_edge.curve())?
.local_on(surface)? .local_on(surface)?
.path; .path;
// assert_eq!(path, path_from_curve);
let surface_coords = path.point_from_path_coords(path_coords); let surface_coords = path.point_from_path_coords(path_coords);
Some( Some(
geometry geometry
@ -188,8 +217,15 @@ fn distances(
let mut distances = Vec::new(); let mut distances = Vec::new();
for i in 0..sample_count { for i in 0..sample_count {
let percent = i as f64 * step; let percent = i as f64 * step;
let sample1 = sample(percent, &half_edge_a, surface_a, geometry)?; let sample1 =
let sample2 = sample(1.0 - percent, &half_edge_b, surface_b, geometry)?; sample(percent, &half_edge_a, end_vertex_a, surface_a, geometry)?;
let sample2 = sample(
1.0 - percent,
&half_edge_b,
end_vertex_b,
surface_b,
geometry,
)?;
distances.push(sample1.distance_to(&sample2)) distances.push(sample1.distance_to(&sample2))
} }
Some(distances.into_iter()) Some(distances.into_iter())

View File

@ -3,7 +3,7 @@ use itertools::Itertools;
use crate::{ use crate::{
geometry::Geometry, geometry::Geometry,
queries::AllHalfEdgesWithSurface, queries::{AllHalfEdgesWithSurface, CycleOfHalfEdge},
storage::Handle, storage::Handle,
topology::{HalfEdge, Shell}, topology::{HalfEdge, Shell},
validation::{ValidationCheck, ValidationConfig}, validation::{ValidationCheck, ValidationConfig},
@ -130,8 +130,28 @@ impl ValidationCheck<Shell> for CurveGeometryMismatch {
// we have right now are circles, 3 would be enough to check // we have right now are circles, 3 would be enough to check
// for coincidence. But the first and last might be // for coincidence. But the first and last might be
// identical, so let's add an extra one. // identical, so let's add an extra one.
let [a, d] = let [a, d] = [
geometry.of_half_edge(&half_edge_a).boundary.inner; geometry
.of_vertex(half_edge_a.start_vertex())
.unwrap()
.local_on(half_edge_a.curve())
.unwrap()
.position,
geometry
.of_vertex(
object
.find_cycle_of_half_edge(&half_edge_a)
.unwrap()
.half_edges()
.after(&half_edge_a)
.unwrap()
.start_vertex(),
)
.unwrap()
.local_on(half_edge_a.curve())
.unwrap()
.position,
];
let b = a + (d - a) * 1. / 3.; let b = a + (d - a) * 1. / 3.;
let c = a + (d - a) * 2. / 3.; let c = a + (d - a) * 2. / 3.;

View File

@ -99,7 +99,12 @@ fn check_cycle<'r>(
) -> impl Iterator<Item = AdjacentHalfEdgesNotConnected> + 'r { ) -> impl Iterator<Item = AdjacentHalfEdgesNotConnected> + 'r {
cycle.half_edges().pairs().filter_map(|(first, second)| { cycle.half_edges().pairs().filter_map(|(first, second)| {
let end_pos_of_first_half_edge = { let end_pos_of_first_half_edge = {
let [_, end] = geometry.of_half_edge(first).boundary.inner; let end = geometry
.of_vertex(second.start_vertex())
.unwrap()
.local_on(first.curve())
.unwrap()
.position;
geometry geometry
.of_curve(first.curve()) .of_curve(first.curve())
.unwrap() .unwrap()
@ -117,9 +122,18 @@ fn check_cycle<'r>(
return None; return None;
}; };
let start_pos_of_second_half_edge = geometry let start_pos_of_second_half_edge = {
.of_half_edge(second) let point_curve = geometry
.start_position(&local_curve_geometry.path); .of_vertex(second.start_vertex())
.unwrap()
.local_on(second.curve())
.unwrap()
.position;
local_curve_geometry
.path
.point_from_path_coords(point_curve)
};
let distance_between_positions = (end_pos_of_first_half_edge let distance_between_positions = (end_pos_of_first_half_edge
- start_pos_of_second_half_edge) - start_pos_of_second_half_edge)