Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve partial object API #1144

Merged
merged 11 commits into from
Sep 27, 2022
89 changes: 52 additions & 37 deletions crates/fj-kernel/src/partial/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use fj_math::{Point, Scalar};

use crate::{
objects::{
Curve, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Surface, Vertex,
Curve, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Surface,
SurfaceVertex, Vertex,
},
stores::{Handle, Stores},
};
Expand Down Expand Up @@ -84,60 +85,77 @@ impl PartialHalfEdge {

/// Update partial half-edge as a line segment, from the given points
pub fn as_line_segment_from_points(
mut self,
self,
surface: Surface,
points: [impl Into<Point<2>>; 2],
) -> Self {
let curve = PartialCurve {
global_form: self.extract_global_curve(),
..PartialCurve::default()
}
.with_surface(surface)
.as_line_from_points(points);

let vertices = [0., 1.].map(|position| {
Vertex::partial()
.with_position([position])
.with_curve(curve.clone())
});

self.curve = Some(curve.into());
self.vertices = Some(vertices.map(Into::into));

self
self.with_vertices(points.map(|point| {
Vertex::partial().with_surface_form(
SurfaceVertex::partial()
.with_surface(surface)
.with_position(point),
)
}))
.as_line_segment()
}

/// Update partial half-edge as a line segment, reusing existing vertices
pub fn as_line_segment(mut self) -> Self {
fn extract_global_curve(
partial: &PartialHalfEdge,
) -> Option<MaybePartial<Handle<GlobalCurve>>> {
fn extract_global_curve_from_curve(
partial: &PartialHalfEdge,
) -> Option<MaybePartial<Handle<GlobalCurve>>> {
partial.curve.as_ref()?.global_form()
}

fn extract_global_curve_from_global_form(
partial: &PartialHalfEdge,
) -> Option<MaybePartial<Handle<GlobalCurve>>> {
Some(partial.global_form.as_ref()?.curve()?.clone().into())
}

extract_global_curve_from_curve(partial)
.or_else(|| extract_global_curve_from_global_form(partial))
}

let [from, to] = self
.vertices
.clone()
.expect("Can't infer line segment without vertices")
.map(|vertex| {
vertex.surface_form().expect(
"Can't infer line segment without two surface vertices",
)
});
.expect("Can't infer line segment without vertices");
let [from_surface, to_surface] = [&from, &to].map(|vertex| {
vertex
.surface_form()
.expect("Can't infer line segment without two surface vertices")
});

let surface = from
let surface = from_surface
.surface()
.copied()
.or_else(|| to.surface().copied())
.or_else(|| to_surface.surface().copied())
.expect("Can't infer line segment without a surface");
let points = [from, to].map(|vertex| {
let points = [&from_surface, &to_surface].map(|vertex| {
vertex
.position()
.expect("Can't infer line segment without surface position")
});

let curve = PartialCurve {
global_form: self.extract_global_curve(),
global_form: extract_global_curve(&self),
..PartialCurve::default()
}
.with_surface(surface)
.as_line_from_points(points);

let vertices = [(from, 0.), (to, 1.)].map(|(vertex, position)| {
vertex.update_partial(|vertex| {
vertex.with_position([position]).with_curve(curve.clone())
})
});

self.curve = Some(curve.into());
self.vertices = Some(vertices);

self
}
Expand All @@ -151,7 +169,11 @@ impl PartialHalfEdge {
let vertices = self
.vertices
.expect("Can't build `HalfEdge` without vertices")
.map(|vertex| vertex.into_full(stores));
.map(|vertex| {
vertex
.update_partial(|vertex| vertex.with_curve(curve.clone()))
.into_full(stores)
});

let global_form = self
.global_form
Expand All @@ -164,13 +186,6 @@ impl PartialHalfEdge {

HalfEdge::new(curve, vertices, global_form)
}

fn extract_global_curve(
&self,
) -> Option<MaybePartial<Handle<GlobalCurve>>> {
let global_curve = self.global_form.as_ref()?.curve()?.clone();
Some(global_curve.into())
}
}

impl From<HalfEdge> for PartialHalfEdge {
Expand Down
23 changes: 22 additions & 1 deletion crates/fj-kernel/src/partial/maybe_partial.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use fj_math::Point;

use crate::{
objects::{GlobalCurve, GlobalEdge, Surface, SurfaceVertex, Vertex},
objects::{Curve, GlobalCurve, GlobalEdge, Surface, SurfaceVertex, Vertex},
stores::{Handle, Stores},
};

Expand All @@ -18,6 +18,17 @@ pub enum MaybePartial<T: HasPartialForm> {
}

impl<T: HasPartialForm> MaybePartial<T> {
/// If this is a partial object, update it
pub fn update_partial(
self,
f: impl FnOnce(T::PartialForm) -> T::PartialForm,
) -> Self {
match self {
Self::Partial(partial) => Self::Partial(f(partial)),
_ => self,
}
}

/// Return the full object, either directly or by building it
pub fn into_full(self, stores: &Stores) -> T {
match self {
Expand All @@ -35,6 +46,16 @@ impl<T: HasPartialForm> MaybePartial<T> {
}
}

impl MaybePartial<Curve> {
/// Access the global form
pub fn global_form(&self) -> Option<MaybePartial<Handle<GlobalCurve>>> {
match self {
Self::Full(full) => Some(full.global_form().clone().into()),
Self::Partial(partial) => partial.global_form.clone(),
}
}
}

impl MaybePartial<GlobalEdge> {
/// Access the curve
pub fn curve(&self) -> Option<&Handle<GlobalCurve>> {
Expand Down