Skip to content

Commit

Permalink
Merge pull request #1140 from hannobraun/ready/partial
Browse files Browse the repository at this point in the history
Make partial object API more flexible
  • Loading branch information
hannobraun authored Sep 26, 2022
2 parents caeeb67 + 66c9124 commit 7d64d1f
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 98 deletions.
40 changes: 23 additions & 17 deletions crates/fj-kernel/src/partial/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use crate::{
stores::{Handle, Stores},
};

use super::MaybePartial;

/// A partial [`Curve`]
///
/// See [`crate::partial`] for more information.
Expand All @@ -25,7 +27,7 @@ pub struct PartialCurve {
///
/// Will be computed from `path` and `surface` in [`PartialCurve::build`],
/// if not provided.
pub global_form: Option<Handle<GlobalCurve>>,
pub global_form: Option<MaybePartial<Handle<GlobalCurve>>>,
}

impl PartialCurve {
Expand All @@ -44,9 +46,9 @@ impl PartialCurve {
/// Provide a global form for the partial curve
pub fn with_global_form(
mut self,
global_form: Handle<GlobalCurve>,
global_form: impl Into<MaybePartial<Handle<GlobalCurve>>>,
) -> Self {
self.global_form = Some(global_form);
self.global_form = Some(global_form.into());
self
}

Expand Down Expand Up @@ -82,19 +84,23 @@ impl PartialCurve {
let surface =
self.surface.expect("Can't build `Curve` without surface");

let global_form = self.global_form.unwrap_or_else(|| {
let path = match path {
SurfacePath::Circle(circle) => {
GlobalPath::circle_from_radius(circle.radius())
}
SurfacePath::Line(line) => GlobalPath::line_from_points(
[line.origin(), line.origin() + line.direction()]
.map(|point| surface.point_from_surface_coords(point)),
),
};

GlobalCurve::partial().with_path(path).build(stores)
});
let global_form = self
.global_form
.unwrap_or_else(|| {
let path = match path {
SurfacePath::Circle(circle) => {
GlobalPath::circle_from_radius(circle.radius())
}
SurfacePath::Line(line) => GlobalPath::line_from_points(
[line.origin(), line.origin() + line.direction()].map(
|point| surface.point_from_surface_coords(point),
),
),
};

GlobalCurve::partial().with_path(path).into()
})
.into_full(stores);

Curve::new(surface, path, global_form)
}
Expand All @@ -105,7 +111,7 @@ impl From<Curve> for PartialCurve {
Self {
path: Some(curve.path()),
surface: Some(*curve.surface()),
global_form: Some(curve.global_form().clone()),
global_form: Some(curve.global_form().clone().into()),
}
}
}
Expand Down
114 changes: 73 additions & 41 deletions crates/fj-kernel/src/partial/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
stores::{Handle, Stores},
};

use super::MaybePartial;
use super::{MaybePartial, PartialCurve};

/// A partial [`HalfEdge`]
///
Expand All @@ -18,12 +18,12 @@ pub struct PartialHalfEdge {
pub curve: Option<MaybePartial<Curve>>,

/// The vertices that bound this [`HalfEdge`] in the [`Curve`]
pub vertices: [Option<MaybePartial<Vertex>>; 2],
pub vertices: Option<[MaybePartial<Vertex>; 2]>,

/// The global form of the [`HalfEdge`]
///
/// Can be computed by [`PartialHalfEdge::build`], if not available.
pub global_form: Option<GlobalEdge>,
pub global_form: Option<MaybePartial<GlobalEdge>>,
}

impl PartialHalfEdge {
Expand All @@ -38,31 +38,16 @@ impl PartialHalfEdge {
mut self,
vertices: [impl Into<MaybePartial<Vertex>>; 2],
) -> Self {
self.vertices = vertices.map(Into::into).map(Some);
self.vertices = Some(vertices.map(Into::into));
self
}

/// Update the partial half-edge, starting it from the given vertex
pub fn with_from_vertex(
mut self,
vertex: impl Into<MaybePartial<Vertex>>,
) -> Self {
self.vertices[0] = Some(vertex.into());
self
}

/// Update the partial half-edge with the given end vertex
pub fn with_to_vertex(
/// Update the partial half-edge with the given global form
pub fn with_global_form(
mut self,
vertex: impl Into<MaybePartial<Vertex>>,
global_form: impl Into<MaybePartial<GlobalEdge>>,
) -> Self {
self.vertices[1] = Some(vertex.into());
self
}

/// Update the partial half-edge with the given global form
pub fn with_global_form(mut self, global_form: GlobalEdge) -> Self {
self.global_form = Some(global_form);
self.global_form = Some(global_form.into());
self
}

Expand Down Expand Up @@ -92,7 +77,7 @@ impl PartialHalfEdge {
};

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

self
}
Expand All @@ -103,9 +88,12 @@ impl PartialHalfEdge {
surface: Surface,
points: [impl Into<Point<2>>; 2],
) -> Self {
let curve = Curve::partial()
.with_surface(surface)
.as_line_from_points(points);
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()
Expand All @@ -114,7 +102,42 @@ impl PartialHalfEdge {
});

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

self
}

/// Update partial half-edge as a line segment, reusing existing vertices
pub fn as_line_segment(mut self) -> Self {
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",
)
});

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

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

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

self
}
Expand All @@ -125,28 +148,37 @@ impl PartialHalfEdge {
.curve
.expect("Can't build `HalfEdge` without curve")
.into_full(stores);
let vertices = self.vertices.map(|vertex| {
vertex
.expect("Can't build `HalfEdge` without vertices")
.into_full(stores)
});

let global_form = self.global_form.unwrap_or_else(|| {
GlobalEdge::partial()
.from_curve_and_vertices(&curve, &vertices)
.build(stores)
});
let vertices = self
.vertices
.expect("Can't build `HalfEdge` without vertices")
.map(|vertex| vertex.into_full(stores));

let global_form = self
.global_form
.unwrap_or_else(|| {
GlobalEdge::partial()
.from_curve_and_vertices(&curve, &vertices)
.into()
})
.into_full(stores);

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 {
fn from(half_edge: HalfEdge) -> Self {
Self {
curve: Some(half_edge.curve().clone().into()),
vertices: half_edge.vertices().clone().map(Into::into).map(Some),
global_form: Some(half_edge.global_form().clone()),
vertices: Some(half_edge.vertices().clone().map(Into::into)),
global_form: Some(half_edge.global_form().clone().into()),
}
}
}
Expand Down
74 changes: 74 additions & 0 deletions crates/fj-kernel/src/partial/maybe_partial.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use fj_math::Point;

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

use super::HasPartialForm;

/// Either a partial object or a full one
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub enum MaybePartial<T: HasPartialForm> {
/// A full object
Full(T),

/// A partial object
Partial(T::PartialForm),
}

impl<T: HasPartialForm> MaybePartial<T> {
/// Return the full object, either directly or by building it
pub fn into_full(self, stores: &Stores) -> T {
match self {
Self::Partial(partial) => T::from_partial(partial, stores),
Self::Full(full) => full,
}
}

/// Return the partial object, either directly or via conversion
pub fn into_partial(self) -> T::PartialForm {
match self {
Self::Partial(partial) => partial,
Self::Full(full) => full.into(),
}
}
}

impl MaybePartial<GlobalEdge> {
/// Access the curve
pub fn curve(&self) -> Option<&Handle<GlobalCurve>> {
match self {
Self::Full(full) => Some(full.curve()),
Self::Partial(partial) => partial.curve.as_ref(),
}
}
}

impl MaybePartial<SurfaceVertex> {
/// Access the position
pub fn position(&self) -> Option<Point<2>> {
match self {
Self::Full(full) => Some(full.position()),
Self::Partial(partial) => partial.position,
}
}

/// Access the surface
pub fn surface(&self) -> Option<&Surface> {
match self {
Self::Full(full) => Some(full.surface()),
Self::Partial(partial) => partial.surface.as_ref(),
}
}
}

impl MaybePartial<Vertex> {
/// Access the surface form
pub fn surface_form(&self) -> Option<MaybePartial<SurfaceVertex>> {
match self {
Self::Full(full) => Some((*full.surface_form()).into()),
Self::Partial(partial) => partial.surface_form.clone(),
}
}
}
30 changes: 2 additions & 28 deletions crates/fj-kernel/src/partial/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@
mod curve;
mod edge;
mod maybe_partial;
mod vertex;

pub use self::{
curve::{PartialCurve, PartialGlobalCurve},
edge::{PartialGlobalEdge, PartialHalfEdge},
maybe_partial::MaybePartial,
vertex::{PartialGlobalVertex, PartialSurfaceVertex, PartialVertex},
};

Expand All @@ -43,34 +45,6 @@ use crate::{
stores::{Handle, Stores},
};

/// Either a partial object or a full one
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub enum MaybePartial<T: HasPartialForm> {
/// A full object
Full(T),

/// A partial object
Partial(T::PartialForm),
}

impl<T: HasPartialForm> MaybePartial<T> {
/// Return the full object, either directly or by building it
pub fn into_full(self, stores: &Stores) -> T {
match self {
Self::Partial(partial) => T::from_partial(partial, stores),
Self::Full(full) => full,
}
}

/// Return the partial object, either directly or via conversion
pub fn into_partial(self) -> T::PartialForm {
match self {
Self::Partial(partial) => partial,
Self::Full(full) => full.into(),
}
}
}

/// Implemented for types that are partial objects
///
/// # Implementation Note
Expand Down
Loading

0 comments on commit 7d64d1f

Please sign in to comment.