Skip to content

Commit

Permalink
Merge pull request #1133 from hannobraun/ready/partial
Browse files Browse the repository at this point in the history
Make it possible to abstract over partial objects
  • Loading branch information
hannobraun authored Sep 23, 2022
2 parents 69b08b8 + 4a72095 commit cdfac1f
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 33 deletions.
2 changes: 1 addition & 1 deletion crates/fj-kernel/src/algorithms/sweep/vertex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ mod tests {
let vertex = Vertex::partial()
.with_position([0.])
.with_curve(curve)
.build();
.build(&stores);

let half_edge = (vertex, surface).sweep([0., 0., 1.], &stores);

Expand Down
4 changes: 2 additions & 2 deletions crates/fj-kernel/src/builder/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl<'a> HalfEdgeBuilder<'a> {

let global_vertex = GlobalVertex::partial()
.from_curve_and_position(&curve, a_curve)
.build();
.build(self.stores);

let surface_vertices = [a_curve, b_curve].map(|point_curve| {
let point_surface =
Expand Down Expand Up @@ -103,7 +103,7 @@ impl<'a> HalfEdgeBuilder<'a> {
let global_vertices = points.map(|position| {
GlobalVertex::partial()
.from_surface_and_position(&self.surface, position)
.build()
.build(self.stores)
});

let surface_vertices = {
Expand Down
59 changes: 38 additions & 21 deletions crates/fj-kernel/src/partial/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
/// A partial [`Curve`]
///
/// See [`crate::partial`] for more information.
#[derive(Default)]
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct PartialCurve {
/// The path that defines the [`Curve`]
///
Expand All @@ -25,7 +25,7 @@ pub struct PartialCurve {
///
/// Will be computed from `path` and `surface` in [`PartialCurve::build`],
/// if not provided.
pub global_form: Option<PartialGlobalCurve>,
pub global_form: Option<Handle<GlobalCurve>>,
}

impl PartialCurve {
Expand All @@ -42,7 +42,10 @@ impl PartialCurve {
}

/// Provide a global form for the partial curve
pub fn with_global_form(mut self, global_form: PartialGlobalCurve) -> Self {
pub fn with_global_form(
mut self,
global_form: Handle<GlobalCurve>,
) -> Self {
self.global_form = Some(global_form);
self
}
Expand Down Expand Up @@ -79,32 +82,38 @@ 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).build(stores)
});

Curve::new(surface, path, global_form)
}
}

impl From<Curve> for PartialCurve {
fn from(curve: Curve) -> Self {
Self {
path: Some(curve.path()),
surface: Some(*curve.surface()),
global_form: Some(curve.global_form().clone()),
}
}
}

/// A partial [`GlobalCurve`]
///
/// See [`crate::partial`] for more information.
#[derive(Default)]
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct PartialGlobalCurve {
/// The path that defines the [`GlobalCurve`]
///
Expand Down Expand Up @@ -154,3 +163,11 @@ impl PartialGlobalCurve {
stores.global_curves.insert(GlobalCurve::from_path(path))
}
}

impl From<Handle<GlobalCurve>> for PartialGlobalCurve {
fn from(global_curve: Handle<GlobalCurve>) -> Self {
Self {
path: Some(global_curve.path()),
}
}
}
87 changes: 87 additions & 0 deletions crates/fj-kernel/src/partial/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,90 @@ pub use self::{
curve::{PartialCurve, PartialGlobalCurve},
vertex::{PartialGlobalVertex, PartialSurfaceVertex, PartialVertex},
};

use crate::{
objects::{Curve, GlobalCurve, GlobalVertex, SurfaceVertex, Vertex},
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
///
/// It would be nicer to require a conversion from `&Self` into the partial
/// form, but I think we need a `where` clause on the associated type to specify
/// that, which is unstable. It should become stable soon though, together with
/// generic associated types:
/// <https://github.com/rust-lang/rust/issues/44265>
pub trait HasPartialForm: Into<Self::PartialForm> {
/// The full version of this partial object
type PartialForm;

/// Build a full object from the partial object
fn from_partial(partial: Self::PartialForm, stores: &Stores) -> Self;
}

macro_rules! impl_traits {
($($full:ty, $partial:ty;)*) => {
$(
impl HasPartialForm for $full {
type PartialForm = $partial;

fn from_partial(partial: Self::PartialForm, stores: &Stores)
-> Self
{
partial.build(stores)
}
}

impl From<$full> for MaybePartial<$full> {
fn from(full: $full) -> Self {
Self::Full(full)
}
}

impl From<$partial> for MaybePartial<$full> {
fn from(partial: $partial) -> Self {
Self::Partial(partial)
}
}
)*
};
}

impl_traits!(
Curve, PartialCurve;
GlobalVertex, PartialGlobalVertex;
SurfaceVertex, PartialSurfaceVertex;
Vertex, PartialVertex;

Handle<GlobalCurve>, PartialGlobalCurve;
);
50 changes: 41 additions & 9 deletions crates/fj-kernel/src/partial/vertex.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use fj_math::Point;

use crate::objects::{Curve, GlobalVertex, Surface, SurfaceVertex, Vertex};
use crate::{
objects::{Curve, GlobalVertex, Surface, SurfaceVertex, Vertex},
stores::Stores,
};

/// A partial [`Vertex`]
///
/// See [`crate::partial`] for more information.
#[derive(Default)]
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct PartialVertex {
/// The position of the [`Vertex`] on the [`Curve`]
///
Expand Down Expand Up @@ -62,7 +65,7 @@ impl PartialVertex {
/// Panics, if no position has been provided.
///
/// Panics, if no curve has been provided.
pub fn build(self) -> Vertex {
pub fn build(self, stores: &Stores) -> Vertex {
let position = self
.position
.expect("Cant' build `Vertex` without position");
Expand All @@ -74,7 +77,7 @@ impl PartialVertex {
surface: Some(*curve.surface()),
global_form: self.global_form,
}
.build()
.build(stores)
});

let global_form = *surface_form.global_form();
Expand All @@ -83,10 +86,21 @@ impl PartialVertex {
}
}

impl From<Vertex> for PartialVertex {
fn from(vertex: Vertex) -> Self {
Self {
position: Some(vertex.position()),
curve: Some(vertex.curve().clone()),
surface_form: Some(*vertex.surface_form()),
global_form: Some(*vertex.global_form()),
}
}
}

/// A partial [`SurfaceVertex`]
///
/// See [`crate::partial`] for more information.
#[derive(Default)]
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct PartialSurfaceVertex {
/// The position of the [`SurfaceVertex`] in the [`Surface`]
///
Expand Down Expand Up @@ -131,7 +145,7 @@ impl PartialSurfaceVertex {
/// Panics, if no position has been provided.
///
/// Panics, if no surface has been provided.
pub fn build(self) -> SurfaceVertex {
pub fn build(self, stores: &Stores) -> SurfaceVertex {
let position = self
.position
.expect("Can't build `SurfaceVertex` without position");
Expand All @@ -142,17 +156,27 @@ impl PartialSurfaceVertex {
let global_form = self.global_form.unwrap_or_else(|| {
GlobalVertex::partial()
.from_surface_and_position(&surface, position)
.build()
.build(stores)
});

SurfaceVertex::new(position, surface, global_form)
}
}

impl From<SurfaceVertex> for PartialSurfaceVertex {
fn from(surface_vertex: SurfaceVertex) -> Self {
Self {
position: Some(surface_vertex.position()),
surface: Some(*surface_vertex.surface()),
global_form: Some(*surface_vertex.global_form()),
}
}
}

/// A partial [`GlobalVertex`]
///
/// See [`crate::partial`] for more information.
#[derive(Default)]
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct PartialGlobalVertex {
/// The position of the [`GlobalVertex`]
///
Expand Down Expand Up @@ -188,11 +212,19 @@ impl PartialGlobalVertex {
}

/// Build a full [`GlobalVertex`] from the partial global vertex
pub fn build(self) -> GlobalVertex {
pub fn build(self, _: &Stores) -> GlobalVertex {
let position = self
.position
.expect("Can't build a `GlobalVertex` without a position");

GlobalVertex::from_position(position)
}
}

impl From<GlobalVertex> for PartialGlobalVertex {
fn from(global_vertex: GlobalVertex) -> Self {
Self {
position: Some(global_vertex.position()),
}
}
}

0 comments on commit cdfac1f

Please sign in to comment.