Merge pull request #2405 from hannobraun/geom

Define vertex geometry in more places
This commit is contained in:
Hanno Braun 2024-06-28 18:55:08 +02:00 committed by GitHub
commit f4676a283f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 407 additions and 166 deletions

View File

@ -2,7 +2,7 @@ use fj_math::{Point, Scalar, Vector};
use itertools::Itertools; use itertools::Itertools;
use crate::{ use crate::{
geometry::LocalVertexGeom, geometry::{CurveBoundary, LocalVertexGeom},
operations::build::BuildHalfEdge, operations::build::BuildHalfEdge,
storage::Handle, storage::Handle,
topology::{Cycle, HalfEdge, Surface}, topology::{Cycle, HalfEdge, Surface},
@ -20,6 +20,38 @@ pub trait BuildCycle {
Cycle::new([]) Cycle::new([])
} }
/// # Build a cycle from half-edges and associated curve boundaries
fn from_half_edges_and_boundaries<I>(
half_edges_and_boundaries: I,
core: &mut Core,
) -> Cycle
where
I: IntoIterator<Item = (Handle<HalfEdge>, CurveBoundary<Point<1>>)>,
I::IntoIter: Clone + ExactSizeIterator,
{
let half_edges = half_edges_and_boundaries
.into_iter()
.circular_tuple_windows()
.map(|((half_edge, boundary), (next_half_edge, _))| {
let [start, end] = boundary.inner;
core.layers.geometry.define_vertex(
half_edge.start_vertex().clone(),
half_edge.curve().clone(),
LocalVertexGeom { position: start },
);
core.layers.geometry.define_vertex(
next_half_edge.start_vertex().clone(),
half_edge.curve().clone(),
LocalVertexGeom { position: end },
);
half_edge
});
Cycle::new(half_edges)
}
/// # Build a circle /// # Build a circle
/// ///
/// This circle is built out of 4 distinct arcs. /// This circle is built out of 4 distinct arcs.
@ -55,14 +87,14 @@ pub trait BuildCycle {
let angle = Scalar::TAU / 4.; let angle = Scalar::TAU / 4.;
let half_edges = let half_edges_and_boundaries = [[a, b], [b, c], [c, d], [d, a]]
[[a, b], [b, c], [c, d], [d, a]] .into_iter()
.into_iter() .map(|[start, end]| {
.map(|[start, end]| { HalfEdge::arc(start, end, angle, surface.clone(), core)
HalfEdge::arc(start, end, angle, surface.clone(), core) })
}); .collect::<Vec<_>>();
Cycle::new(half_edges) Self::from_half_edges_and_boundaries(half_edges_and_boundaries, core)
} }
/// Build a polygon /// Build a polygon
@ -84,27 +116,8 @@ pub trait BuildCycle {
HalfEdge::line_segment([start, end], surface.clone(), core) HalfEdge::line_segment([start, end], surface.clone(), core)
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let half_edges = half_edges_and_boundaries
.into_iter()
.circular_tuple_windows()
.map(|((half_edge, boundary), (next_half_edge, _))| {
let [start, end] = boundary.inner;
core.layers.geometry.define_vertex( Self::from_half_edges_and_boundaries(half_edges_and_boundaries, core)
half_edge.start_vertex().clone(),
half_edge.curve().clone(),
LocalVertexGeom { position: start },
);
core.layers.geometry.define_vertex(
next_half_edge.start_vertex().clone(),
half_edge.curve().clone(),
LocalVertexGeom { position: end },
);
half_edge
});
Cycle::new(half_edges)
} }
} }

View File

@ -50,7 +50,7 @@ pub trait BuildHalfEdge {
angle_rad: impl Into<Scalar>, angle_rad: impl Into<Scalar>,
surface: Handle<Surface>, surface: Handle<Surface>,
core: &mut Core, core: &mut Core,
) -> Handle<HalfEdge> { ) -> (Handle<HalfEdge>, CurveBoundary<Point<1>>) {
let angle_rad = angle_rad.into(); let angle_rad = angle_rad.into();
if angle_rad <= -Scalar::TAU || angle_rad >= Scalar::TAU { if angle_rad <= -Scalar::TAU || angle_rad >= Scalar::TAU {
panic!("arc angle must be in the range (-2pi, 2pi) radians"); panic!("arc angle must be in the range (-2pi, 2pi) radians");
@ -60,8 +60,10 @@ pub trait BuildHalfEdge {
let path = let path =
SurfacePath::circle_from_center_and_radius(arc.center, arc.radius); SurfacePath::circle_from_center_and_radius(arc.center, arc.radius);
let boundary = let boundary = CurveBoundary {
[arc.start_angle, arc.end_angle].map(|coord| Point::from([coord])); inner: [arc.start_angle, arc.end_angle]
.map(|coord| Point::from([coord])),
};
let half_edge = HalfEdge::unjoined(core).insert(core); let half_edge = HalfEdge::unjoined(core).insert(core);
@ -70,14 +72,11 @@ pub trait BuildHalfEdge {
surface, surface,
LocalCurveGeom { path }, LocalCurveGeom { path },
); );
core.layers.geometry.define_half_edge( core.layers
half_edge.clone(), .geometry
HalfEdgeGeom { .define_half_edge(half_edge.clone(), HalfEdgeGeom { boundary });
boundary: boundary.into(),
},
);
half_edge (half_edge, boundary)
} }
/// Create a line segment /// Create a line segment

View File

@ -182,8 +182,15 @@ pub trait BuildShell {
cycle cycle
.update_half_edge( .update_half_edge(
cycle.half_edges().nth_circular(0), cycle.half_edges().nth_circular(0),
|edge, core| { |half_edge, core| {
[(edge, bad.face.surface()) [(
half_edge,
cycle
.half_edges()
.nth_circular(1)
.start_vertex(),
bad.face.surface(),
)
.reverse_curve_coordinate_systems( .reverse_curve_coordinate_systems(
core, core,
)] )]
@ -204,111 +211,154 @@ pub trait BuildShell {
core, core,
) )
}; };
let dac = let dac = {
{ let dac = Face::triangle([d, a, c], core);
let dac = Face::triangle([d, a, c], core); dac.update_region(
dac.update_region( |region, core| {
|region, core| { region.update_exterior(
region.update_exterior( |cycle, core| {
|cycle, core| { cycle
cycle .update_half_edge(
.update_half_edge( cycle.half_edges().nth_circular(1),
cycle.half_edges().nth_circular(1), |half_edge, core| {
|edge, core| { [(
[(edge, dac.face.surface()) half_edge,
.reverse_curve_coordinate_systems(core)] cycle
}, .half_edges()
core, .nth_circular(2)
) .start_vertex(),
.join_to( dac.face.surface(),
abc.face.region().exterior(), )
1..=1, .reverse_curve_coordinate_systems(
2..=2, core,
dac.face.surface().clone(), )]
core, },
) core,
.update_half_edge( )
cycle.half_edges().nth_circular(0), .join_to(
|edge, core| { abc.face.region().exterior(),
[(edge, dac.face.surface()) 1..=1,
.reverse_curve_coordinate_systems(core)] 2..=2,
}, dac.face.surface().clone(),
core, core,
) )
.join_to( .update_half_edge(
bad.face.region().exterior(), cycle.half_edges().nth_circular(0),
0..=0, |half_edge, core| {
1..=1, [(
dac.face.surface().clone(), half_edge,
core, cycle
) .half_edges()
}, .nth_circular(1)
core, .start_vertex(),
) dac.face.surface(),
}, )
core, .reverse_curve_coordinate_systems(
) core,
}; )]
let cbd = },
{ core,
let cbd = Face::triangle([c, b, d], core); )
cbd.update_region( .join_to(
|region, core| { bad.face.region().exterior(),
region.update_exterior( 0..=0,
|cycle, core| { 1..=1,
cycle dac.face.surface().clone(),
.update_half_edge( core,
cycle.half_edges().nth_circular(0), )
|edge, core| { },
[(edge, cbd.face.surface()) core,
.reverse_curve_coordinate_systems(core)] )
}, },
core, core,
) )
.update_half_edge( };
cycle.half_edges().nth_circular(1), let cbd = {
|edge, core| { let cbd = Face::triangle([c, b, d], core);
[(edge, cbd.face.surface()) cbd.update_region(
.reverse_curve_coordinate_systems(core)] |region, core| {
}, region.update_exterior(
core, |cycle, core| {
) cycle
.update_half_edge( .update_half_edge(
cycle.half_edges().nth_circular(2), cycle.half_edges().nth_circular(0),
|edge, core| { |half_edge, core| {
[(edge, cbd.face.surface()) [(
.reverse_curve_coordinate_systems(core)] half_edge,
}, cycle
core, .half_edges()
) .nth_circular(1)
.join_to( .start_vertex(),
abc.face.region().exterior(), cbd.face.surface(),
0..=0, )
1..=1, .reverse_curve_coordinate_systems(
cbd.face.surface().clone(), core,
core, )]
) },
.join_to( core,
bad.face.region().exterior(), )
1..=1, .update_half_edge(
2..=2, cycle.half_edges().nth_circular(1),
cbd.face.surface().clone(), |half_edge, core| {
core, [(
) half_edge,
.join_to( cycle
dac.face.region().exterior(), .half_edges()
2..=2, .nth_circular(2)
2..=2, .start_vertex(),
cbd.face.surface().clone(), cbd.face.surface(),
core, )
) .reverse_curve_coordinate_systems(
}, core,
core, )]
) },
}, core,
core, )
) .update_half_edge(
}; cycle.half_edges().nth_circular(2),
|half_edge, core| {
[(
half_edge,
cycle
.half_edges()
.nth_circular(3)
.start_vertex(),
cbd.face.surface(),
)
.reverse_curve_coordinate_systems(
core,
)]
},
core,
)
.join_to(
abc.face.region().exterior(),
0..=0,
1..=1,
cbd.face.surface().clone(),
core,
)
.join_to(
bad.face.region().exterior(),
1..=1,
2..=2,
cbd.face.surface().clone(),
core,
)
.join_to(
dac.face.region().exterior(),
2..=2,
2..=2,
cbd.face.surface().clone(),
core,
)
},
core,
)
},
core,
)
};
let triangles = let triangles =
[abc, bad, dac, cbd].map(|triangle| triangle.insert(core)); [abc, bad, dac, cbd].map(|triangle| triangle.insert(core));

View File

@ -154,11 +154,16 @@ impl JoinCycle for Cycle {
range.zip(range_other).fold( range.zip(range_other).fold(
self.clone(), self.clone(),
|cycle, (index, index_other)| { |cycle, (index, index_other)| {
let edge_other = other.half_edges().nth_circular(index_other); let half_edge = self.half_edges().nth_circular(index);
let half_edge_next = self.half_edges().nth_circular(index + 1);
let half_edge_other =
other.half_edges().nth_circular(index_other);
let half_edge_other_next =
other.half_edges().nth_circular(index_other + 1);
cycle cycle
.update_half_edge( .update_half_edge(
self.half_edges().nth_circular(index), half_edge,
|half_edge, core| { |half_edge, core| {
// The curve of the other half-edge we're joining // The curve of the other half-edge we're joining
// this one to already has a curve geometry, // this one to already has a curve geometry,
@ -178,22 +183,78 @@ impl JoinCycle for Cycle {
}); });
if let Some(curve_geom) = curve_geom { if let Some(curve_geom) = curve_geom {
core.layers.geometry.define_curve( core.layers.geometry.define_curve(
edge_other.curve().clone(), half_edge_other.curve().clone(),
surface_self.clone(), surface_self.clone(),
curve_geom.clone(), curve_geom.clone(),
); );
} }
// The same goes for vertices. We have to move over
// any local definitions we have to the other
// vertices.
let vertex_geom_prev_end = core
.layers
.geometry
.of_vertex(half_edge.start_vertex())
.and_then(|vertex_geom| {
vertex_geom.local_on(
self.half_edges()
.before(half_edge)
.unwrap()
.curve(),
)
})
.cloned();
let vertex_geom_start = core
.layers
.geometry
.of_vertex(half_edge.start_vertex())
.and_then(|vertex_geom| {
vertex_geom.local_on(half_edge.curve())
})
.cloned();
let vertex_geom_end = core
.layers
.geometry
.of_vertex(half_edge_next.start_vertex())
.and_then(|vertex_geom| {
vertex_geom.local_on(half_edge.curve())
})
.cloned();
if let Some(vertex_geom) = vertex_geom_prev_end {
core.layers.geometry.define_vertex(
half_edge_other_next.start_vertex().clone(),
self.half_edges()
.before(half_edge)
.unwrap()
.curve()
.clone(),
vertex_geom,
);
}
if let Some(vertex_geom_start) = vertex_geom_start {
core.layers.geometry.define_vertex(
half_edge_other_next.start_vertex().clone(),
half_edge_other.curve().clone(),
vertex_geom_start,
);
}
if let Some(vertex_geom_end) = vertex_geom_end {
core.layers.geometry.define_vertex(
half_edge_other.start_vertex().clone(),
half_edge_other.curve().clone(),
vertex_geom_end,
);
}
[half_edge [half_edge
.update_curve( .update_curve(
|_, _| edge_other.curve().clone(), |_, _| half_edge_other.curve().clone(),
core, core,
) )
.update_start_vertex( .update_start_vertex(
|_, _| { |_, _| {
other half_edge_other_next
.half_edges()
.nth_circular(index_other + 1)
.start_vertex() .start_vertex()
.clone() .clone()
}, },
@ -211,11 +272,31 @@ impl JoinCycle for Cycle {
core, core,
) )
.update_half_edge( .update_half_edge(
self.half_edges().nth_circular(index + 1), half_edge_next,
|half_edge, core| { |half_edge, core| {
// And we need to move over the geometry for this
// vertex too.
let vertex_geom = core
.layers
.geometry
.of_vertex(half_edge_next.start_vertex())
.and_then(|vertex_geom| {
vertex_geom.local_on(half_edge_next.curve())
})
.cloned();
if let Some(vertex_geom) = vertex_geom {
core.layers.geometry.define_vertex(
half_edge_other.start_vertex().clone(),
half_edge.curve().clone(),
vertex_geom,
);
}
[half_edge [half_edge
.update_start_vertex( .update_start_vertex(
|_, _| edge_other.start_vertex().clone(), |_, _| {
half_edge_other.start_vertex().clone()
},
core, core,
) )
.insert(core) .insert(core)

View File

@ -14,8 +14,9 @@ impl Reverse for Cycle {
.half_edges() .half_edges()
.pairs() .pairs()
.map(|(current, next)| { .map(|(current, next)| {
let mut geometry = *core.layers.geometry.of_half_edge(current); let mut half_edge_geom =
geometry.boundary = geometry.boundary.reverse(); *core.layers.geometry.of_half_edge(current);
half_edge_geom.boundary = half_edge_geom.boundary.reverse();
HalfEdge::new( HalfEdge::new(
current.curve().clone(), current.curve().clone(),
@ -23,7 +24,7 @@ impl Reverse for Cycle {
) )
.insert(core) .insert(core)
.derive_from(current, core) .derive_from(current, core)
.set_geometry(geometry, &mut core.layers.geometry) .set_geometry(half_edge_geom, &mut core.layers.geometry)
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();

View File

@ -1,20 +1,39 @@
use crate::{ use crate::{
operations::{derive::DeriveFrom, insert::Insert}, operations::{derive::DeriveFrom, insert::Insert},
storage::Handle, storage::Handle,
topology::{HalfEdge, Surface}, topology::{HalfEdge, Surface, Vertex},
Core, Core,
}; };
use super::ReverseCurveCoordinateSystems; use super::ReverseCurveCoordinateSystems;
impl ReverseCurveCoordinateSystems for (&Handle<HalfEdge>, &Handle<Surface>) { impl ReverseCurveCoordinateSystems
for (&Handle<HalfEdge>, &Handle<Vertex>, &Handle<Surface>)
{
type Reversed = Handle<HalfEdge>; type Reversed = Handle<HalfEdge>;
fn reverse_curve_coordinate_systems( fn reverse_curve_coordinate_systems(
self, self,
core: &mut Core, core: &mut Core,
) -> Self::Reversed { ) -> Self::Reversed {
let (half_edge, surface) = self; let (half_edge, end_vertex, surface) = self;
let vertex_geom_start = core
.layers
.geometry
.of_vertex(half_edge.start_vertex())
.unwrap()
.local_on(half_edge.curve())
.unwrap()
.clone();
let vertex_geom_end = core
.layers
.geometry
.of_vertex(end_vertex)
.unwrap()
.local_on(half_edge.curve())
.unwrap()
.clone();
let mut half_edge_geom = *core.layers.geometry.of_half_edge(half_edge); let mut half_edge_geom = *core.layers.geometry.of_half_edge(half_edge);
half_edge_geom.boundary = half_edge_geom.boundary.reverse(); half_edge_geom.boundary = half_edge_geom.boundary.reverse();
@ -26,6 +45,17 @@ impl ReverseCurveCoordinateSystems for (&Handle<HalfEdge>, &Handle<Surface>) {
.insert(core) .insert(core)
.derive_from(half_edge, core); .derive_from(half_edge, core);
core.layers.geometry.define_vertex(
half_edge.start_vertex().clone(),
half_edge.curve().clone(),
vertex_geom_end,
);
core.layers.geometry.define_vertex(
end_vertex.clone(),
half_edge.curve().clone(),
vertex_geom_start,
);
core.layers core.layers
.geometry .geometry
.define_half_edge(half_edge.clone(), half_edge_geom); .define_half_edge(half_edge.clone(), half_edge_geom);

View File

@ -266,6 +266,37 @@ mod tests {
&mut core.layers.geometry, &mut core.layers.geometry,
); );
let start_vertex =
half_edge.start_vertex();
let end_vertex = cycle
.half_edges()
.after(half_edge)
.unwrap()
.start_vertex();
core.layers.geometry.define_vertex(
start_vertex.clone(),
curve.clone(),
core.layers
.geometry
.of_vertex(start_vertex)
.unwrap()
.local_on(half_edge.curve())
.unwrap()
.clone(),
);
core.layers.geometry.define_vertex(
end_vertex.clone(),
curve.clone(),
core.layers
.geometry
.of_vertex(end_vertex)
.unwrap()
.local_on(half_edge.curve())
.unwrap()
.clone(),
);
[half_edge [half_edge
.update_curve(|_, _| curve, core) .update_curve(|_, _| curve, core)
.insert(core) .insert(core)

View File

@ -142,6 +142,7 @@ fn check_cycle<'r>(
mod tests { mod tests {
use crate::{ use crate::{
geometry::LocalVertexGeom,
operations::{ operations::{
build::{BuildFace, BuildHalfEdge}, build::{BuildFace, BuildHalfEdge},
update::{UpdateCycle, UpdateFace, UpdateRegion}, update::{UpdateCycle, UpdateFace, UpdateRegion},
@ -178,12 +179,47 @@ mod tests {
cycle.update_half_edge( cycle.update_half_edge(
cycle.half_edges().first(), cycle.half_edges().first(),
|_, core| { |_, core| {
[HalfEdge::line_segment( let (half_edge, boundary) =
[[0., 0.], [2., 0.]], HalfEdge::line_segment(
surface, [[0., 0.], [2., 0.]],
core, surface,
) core,
.0] );
let half_edge_prev =
cycle.half_edges().nth(2).unwrap();
let half_edge_next = cycle
.half_edges()
.nth(1)
.unwrap()
.start_vertex()
.clone();
core.layers.geometry.define_vertex(
half_edge.start_vertex().clone(),
half_edge_prev.curve().clone(),
core.layers
.geometry
.of_vertex(
cycle
.half_edges()
.first()
.start_vertex(),
)
.unwrap()
.local_on(half_edge_prev.curve())
.unwrap()
.clone(),
);
core.layers.geometry.define_vertex(
half_edge_next,
half_edge.curve().clone(),
LocalVertexGeom {
position: boundary.inner[1],
},
);
[half_edge]
}, },
core, core,
) )