mirror of https://github.com/hannobraun/Fornjot
Extract builder methods from `PartialCycle`
This commit is contained in:
parent
9a6c72caaf
commit
f4bf0aa8cf
|
@ -0,0 +1,134 @@
|
|||
use fj_math::Point;
|
||||
|
||||
use crate::{
|
||||
objects::{Curve, HalfEdge, SurfaceVertex, Vertex},
|
||||
partial::{HasPartial, MaybePartial, PartialCycle},
|
||||
};
|
||||
|
||||
use super::{CurveBuilder, HalfEdgeBuilder};
|
||||
|
||||
/// Builder API for [`PartialCycle`]
|
||||
pub trait CycleBuilder {
|
||||
/// Update the partial cycle with a polygonal chain from the provided points
|
||||
fn with_poly_chain(
|
||||
self,
|
||||
vertices: impl IntoIterator<Item = MaybePartial<SurfaceVertex>>,
|
||||
) -> Self;
|
||||
|
||||
/// Update the partial cycle with a polygonal chain from the provided points
|
||||
fn with_poly_chain_from_points(
|
||||
self,
|
||||
points: impl IntoIterator<Item = impl Into<Point<2>>>,
|
||||
) -> Self;
|
||||
|
||||
/// Update the partial cycle by closing it with a line segment
|
||||
///
|
||||
/// Builds a line segment from the last and first vertex, closing the cycle.
|
||||
fn close_with_line_segment(self) -> Self;
|
||||
}
|
||||
|
||||
impl CycleBuilder for PartialCycle {
|
||||
fn with_poly_chain(
|
||||
self,
|
||||
vertices: impl IntoIterator<Item = MaybePartial<SurfaceVertex>>,
|
||||
) -> Self {
|
||||
let iter = self
|
||||
.half_edges()
|
||||
.last()
|
||||
.map(|half_edge| {
|
||||
let [_, last] = half_edge.vertices();
|
||||
last.surface_form()
|
||||
})
|
||||
.into_iter()
|
||||
.chain(vertices);
|
||||
|
||||
let mut previous: Option<MaybePartial<SurfaceVertex>> = None;
|
||||
|
||||
let mut half_edges = Vec::new();
|
||||
for vertex_next in iter {
|
||||
if let Some(vertex_prev) = previous {
|
||||
let surface = self
|
||||
.surface()
|
||||
.clone()
|
||||
.expect("Need surface to extend cycle with poly-chain");
|
||||
|
||||
let position_prev = vertex_prev
|
||||
.position()
|
||||
.expect("Need surface position to extend cycle");
|
||||
let position_next = vertex_next
|
||||
.position()
|
||||
.expect("Need surface position to extend cycle");
|
||||
|
||||
let from = vertex_prev.update_partial(|partial| {
|
||||
partial.with_surface(Some(surface.clone()))
|
||||
});
|
||||
let to = vertex_next.update_partial(|partial| {
|
||||
partial.with_surface(Some(surface.clone()))
|
||||
});
|
||||
|
||||
previous = Some(to.clone());
|
||||
|
||||
let curve = Curve::partial()
|
||||
.with_surface(Some(surface.clone()))
|
||||
.update_as_line_from_points([position_prev, position_next]);
|
||||
|
||||
let [from, to] =
|
||||
[(0., from), (1., to)].map(|(position, surface_form)| {
|
||||
Vertex::partial()
|
||||
.with_curve(Some(curve.clone()))
|
||||
.with_position(Some([position]))
|
||||
.with_surface_form(Some(surface_form))
|
||||
});
|
||||
|
||||
half_edges.push(
|
||||
HalfEdge::partial()
|
||||
.with_curve(Some(curve))
|
||||
.with_vertices(Some([from, to])),
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
previous = Some(vertex_next);
|
||||
}
|
||||
|
||||
self.with_half_edges(half_edges)
|
||||
}
|
||||
|
||||
fn with_poly_chain_from_points(
|
||||
self,
|
||||
points: impl IntoIterator<Item = impl Into<Point<2>>>,
|
||||
) -> Self {
|
||||
self.with_poly_chain(points.into_iter().map(|position| {
|
||||
SurfaceVertex::partial()
|
||||
.with_position(Some(position))
|
||||
.into()
|
||||
}))
|
||||
}
|
||||
|
||||
fn close_with_line_segment(self) -> Self {
|
||||
let first = self.half_edges().next();
|
||||
let last = self.half_edges().last();
|
||||
|
||||
let vertices = [first, last]
|
||||
.map(|option| option.map(|half_edge| half_edge.vertices()));
|
||||
|
||||
let [Some([first, _]), Some([_, last])] = vertices else {
|
||||
return self;
|
||||
};
|
||||
|
||||
let vertices = [last, first].map(|vertex| {
|
||||
vertex
|
||||
.surface_form()
|
||||
.position()
|
||||
.expect("Need surface position to close cycle")
|
||||
});
|
||||
let surface = self.surface().expect("Need surface to close cycle");
|
||||
|
||||
self.with_half_edges(Some(
|
||||
HalfEdge::partial()
|
||||
.with_surface(Some(surface))
|
||||
.update_as_line_segment_from_points(vertices),
|
||||
))
|
||||
}
|
||||
}
|
|
@ -7,6 +7,8 @@ use crate::{
|
|||
storage::Handle,
|
||||
};
|
||||
|
||||
use super::CycleBuilder;
|
||||
|
||||
/// API for building a [`Face`]
|
||||
///
|
||||
/// Also see [`Face::builder`].
|
||||
|
|
|
@ -10,11 +10,13 @@ mod solid;
|
|||
|
||||
// These are new-style builders that build on top of the partial object API.
|
||||
mod curve;
|
||||
mod cycle;
|
||||
mod edge;
|
||||
mod vertex;
|
||||
|
||||
pub use self::{
|
||||
curve::CurveBuilder,
|
||||
cycle::CycleBuilder,
|
||||
edge::{GlobalEdgeBuilder, HalfEdgeBuilder},
|
||||
face::FaceBuilder,
|
||||
shell::ShellBuilder,
|
||||
|
|
|
@ -360,7 +360,7 @@ impl<T> Iterator for Iter<T> {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
builder::{CurveBuilder, HalfEdgeBuilder},
|
||||
builder::{CurveBuilder, CycleBuilder, HalfEdgeBuilder},
|
||||
objects::{
|
||||
Curve, Cycle, Face, GlobalCurve, GlobalVertex, HalfEdge, Objects,
|
||||
Shell, Sketch, Solid, SurfaceVertex, Vertex,
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
use fj_math::Point;
|
||||
|
||||
use crate::{
|
||||
builder::{CurveBuilder, HalfEdgeBuilder},
|
||||
objects::{
|
||||
Curve, Cycle, HalfEdge, Objects, Surface, SurfaceVertex, Vertex,
|
||||
},
|
||||
partial::{HasPartial, MaybePartial},
|
||||
objects::{Cycle, HalfEdge, Objects, Surface},
|
||||
partial::MaybePartial,
|
||||
storage::Handle,
|
||||
validate::ValidationError,
|
||||
};
|
||||
|
@ -48,115 +43,6 @@ impl PartialCycle {
|
|||
self
|
||||
}
|
||||
|
||||
/// Update the partial cycle with a polygonal chain from the provided points
|
||||
pub fn with_poly_chain(
|
||||
self,
|
||||
vertices: impl IntoIterator<Item = MaybePartial<SurfaceVertex>>,
|
||||
) -> Self {
|
||||
let iter = self
|
||||
.half_edges()
|
||||
.last()
|
||||
.map(|half_edge| {
|
||||
let [_, last] = half_edge.vertices();
|
||||
last.surface_form()
|
||||
})
|
||||
.into_iter()
|
||||
.chain(vertices);
|
||||
|
||||
let mut previous: Option<MaybePartial<SurfaceVertex>> = None;
|
||||
|
||||
let mut half_edges = Vec::new();
|
||||
for vertex_next in iter {
|
||||
if let Some(vertex_prev) = previous {
|
||||
let surface = self
|
||||
.surface()
|
||||
.clone()
|
||||
.expect("Need surface to extend cycle with poly-chain");
|
||||
|
||||
let position_prev = vertex_prev
|
||||
.position()
|
||||
.expect("Need surface position to extend cycle");
|
||||
let position_next = vertex_next
|
||||
.position()
|
||||
.expect("Need surface position to extend cycle");
|
||||
|
||||
let from = vertex_prev.update_partial(|partial| {
|
||||
partial.with_surface(Some(surface.clone()))
|
||||
});
|
||||
let to = vertex_next.update_partial(|partial| {
|
||||
partial.with_surface(Some(surface.clone()))
|
||||
});
|
||||
|
||||
previous = Some(to.clone());
|
||||
|
||||
let curve = Curve::partial()
|
||||
.with_surface(Some(surface.clone()))
|
||||
.update_as_line_from_points([position_prev, position_next]);
|
||||
|
||||
let [from, to] =
|
||||
[(0., from), (1., to)].map(|(position, surface_form)| {
|
||||
Vertex::partial()
|
||||
.with_curve(Some(curve.clone()))
|
||||
.with_position(Some([position]))
|
||||
.with_surface_form(Some(surface_form))
|
||||
});
|
||||
|
||||
half_edges.push(
|
||||
HalfEdge::partial()
|
||||
.with_curve(Some(curve))
|
||||
.with_vertices(Some([from, to])),
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
previous = Some(vertex_next);
|
||||
}
|
||||
|
||||
self.with_half_edges(half_edges)
|
||||
}
|
||||
|
||||
/// Update the partial cycle with a polygonal chain from the provided points
|
||||
pub fn with_poly_chain_from_points(
|
||||
self,
|
||||
points: impl IntoIterator<Item = impl Into<Point<2>>>,
|
||||
) -> Self {
|
||||
self.with_poly_chain(points.into_iter().map(|position| {
|
||||
SurfaceVertex::partial()
|
||||
.with_position(Some(position))
|
||||
.into()
|
||||
}))
|
||||
}
|
||||
|
||||
/// Update the partial cycle by closing it with a line segment
|
||||
///
|
||||
/// Builds a line segment from the last and first vertex, closing the cycle.
|
||||
pub fn close_with_line_segment(self) -> Self {
|
||||
let first = self.half_edges().next();
|
||||
let last = self.half_edges().last();
|
||||
|
||||
let vertices = [first, last]
|
||||
.map(|option| option.map(|half_edge| half_edge.vertices()));
|
||||
|
||||
let [Some([first, _]), Some([_, last])] = vertices else {
|
||||
return self;
|
||||
};
|
||||
|
||||
let vertices = [last, first].map(|vertex| {
|
||||
vertex
|
||||
.surface_form()
|
||||
.position()
|
||||
.expect("Need surface position to close cycle")
|
||||
});
|
||||
let surface = self.surface().expect("Need surface to close cycle");
|
||||
|
||||
self.with_half_edges(Some(
|
||||
HalfEdge::partial()
|
||||
.with_surface(Some(surface))
|
||||
.update_as_line_segment_from_points(vertices),
|
||||
))
|
||||
}
|
||||
|
||||
/// Build a full [`Cycle`] from the partial cycle
|
||||
pub fn build(
|
||||
mut self,
|
||||
|
|
Loading…
Reference in New Issue