Skip to content

Commit

Permalink
Merge pull request #1428 from hannobraun/partial
Browse files Browse the repository at this point in the history
Introduce new partial object API
  • Loading branch information
hannobraun authored Dec 7, 2022
2 parents 42a8d4f + a556f95 commit 045255a
Show file tree
Hide file tree
Showing 15 changed files with 1,022 additions and 1 deletion.
1 change: 1 addition & 0 deletions crates/fj-kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ pub mod insert;
pub mod iter;
pub mod objects;
pub mod partial;
pub mod partial2;
pub mod services;
pub mod storage;
pub mod validate;
31 changes: 31 additions & 0 deletions crates/fj-kernel/src/partial2/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//! Partially defined objects
//!
//! This module contains types that mirror the full object types from
//! [`crate::objects`], only the types from this module can be defined only
//! partially, with the non-defined parts being inferred when a full object is
//! constructed.
//!
//! # Implementation Note
//!
//! This API was created as a replacement for the [original partial object
//! API][crate::partial]. This is still a work in progress.

mod objects;
mod traits;
mod wrapper;

pub use self::{
objects::{
curve::{PartialCurve, PartialGlobalCurve},
cycle::PartialCycle,
edge::{PartialGlobalEdge, PartialHalfEdge},
face::PartialFace,
shell::PartialShell,
sketch::PartialSketch,
solid::PartialSolid,
surface::PartialSurface,
vertex::{PartialGlobalVertex, PartialSurfaceVertex, PartialVertex},
},
traits::{HasPartial, PartialObject},
wrapper::{FullToPartialCache, Partial},
};
92 changes: 92 additions & 0 deletions crates/fj-kernel/src/partial2/objects/curve.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use crate::{
geometry::path::SurfacePath,
objects::{Curve, GlobalCurve, Objects, Surface},
partial2::{FullToPartialCache, Partial, PartialObject},
services::Service,
};

/// A partial [`Curve`]
#[derive(Clone, Debug)]
pub struct PartialCurve {
/// The path that defines the curve
pub path: Option<SurfacePath>,

/// The surface the curve is defined in
pub surface: Partial<Surface>,

/// The global form of the curve
pub global_form: Partial<GlobalCurve>,
}

impl PartialCurve {
/// Construct an instance of `PartialCurve`
pub fn new(
path: Option<SurfacePath>,
surface: Option<Partial<Surface>>,
global_form: Option<Partial<GlobalCurve>>,
) -> Self {
let surface = surface.unwrap_or_default();
let global_form = global_form.unwrap_or_default();

Self {
path,
surface,
global_form,
}
}
}

impl PartialObject for PartialCurve {
type Full = Curve;

fn from_full(curve: &Self::Full, cache: &mut FullToPartialCache) -> Self {
Self::new(
Some(curve.path()),
Some(Partial::from_full(curve.surface().clone(), cache)),
Some(Partial::from_full(curve.global_form().clone(), cache)),
)
}

fn build(self, objects: &mut Service<Objects>) -> Self::Full {
let path = self.path.expect("Need path to build curve");
let surface = self.surface.build(objects);
let global_form = self.global_form.build(objects);

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

impl Default for PartialCurve {
fn default() -> Self {
Self::new(None, None, None)
}
}

/// A partial [`GlobalCurve`]
#[derive(Clone, Debug)]
pub struct PartialGlobalCurve;

impl PartialGlobalCurve {
/// Construct an instance of `PartialGlobalCurve`
pub fn new() -> Self {
Self
}
}

impl PartialObject for PartialGlobalCurve {
type Full = GlobalCurve;

fn from_full(_: &Self::Full, _: &mut FullToPartialCache) -> Self {
Self::new()
}

fn build(self, _: &mut Service<Objects>) -> Self::Full {
GlobalCurve
}
}

impl Default for PartialGlobalCurve {
fn default() -> Self {
Self::new()
}
}
48 changes: 48 additions & 0 deletions crates/fj-kernel/src/partial2/objects/cycle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use crate::{
objects::{Cycle, HalfEdge, Objects},
partial2::{FullToPartialCache, Partial, PartialObject},
services::Service,
};

/// A partial [`Cycle`]
#[derive(Clone, Debug)]
pub struct PartialCycle {
/// The half-edges that make up the cycle
pub half_edges: Vec<Partial<HalfEdge>>,
}

impl PartialCycle {
/// Construct an instance of `PartialCycle`
pub fn new(half_edges: Vec<Partial<HalfEdge>>) -> Self {
Self { half_edges }
}
}

impl PartialObject for PartialCycle {
type Full = Cycle;

fn from_full(cycle: &Self::Full, cache: &mut FullToPartialCache) -> Self {
Self::new(
cycle
.half_edges()
.cloned()
.map(|half_edge| Partial::from_full(half_edge, cache))
.collect(),
)
}

fn build(self, objects: &mut Service<Objects>) -> Self::Full {
let half_edges = self
.half_edges
.into_iter()
.map(|half_edge| half_edge.build(objects));

Cycle::new(half_edges)
}
}

impl Default for PartialCycle {
fn default() -> Self {
Self::new(Vec::new())
}
}
142 changes: 142 additions & 0 deletions crates/fj-kernel/src/partial2/objects/edge.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
use fj_interop::ext::ArrayExt;

use crate::{
objects::{
Curve, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Objects, Vertex,
},
partial2::{FullToPartialCache, Partial, PartialObject, PartialVertex},
services::Service,
};

/// A partial [`HalfEdge`]
#[derive(Clone, Debug)]
pub struct PartialHalfEdge {
/// The vertices that bound the half-edge on the curve
pub vertices: [Partial<Vertex>; 2],

/// The global form of the half-edge
pub global_form: Partial<GlobalEdge>,
}

impl PartialHalfEdge {
/// Construct an instance of `PartialHalfEdge`
pub fn new(
vertices: [Option<Partial<Vertex>>; 2],
global_form: Option<Partial<GlobalEdge>>,
) -> Self {
let curve = Partial::<Curve>::new();

let vertices = vertices.map(|vertex| {
vertex.unwrap_or_else(|| {
Partial::from_partial(PartialVertex::new(
None,
Some(curve.clone()),
None,
))
})
});

let global_curve = curve.read().global_form.clone();
let global_vertices =
vertices.each_ref_ext().map(|vertex: &Partial<Vertex>| {
let surface_vertex = vertex.read().surface_form.clone();
let global_vertex = surface_vertex.read().global_form.clone();
Some(global_vertex)
});

let global_form = global_form.unwrap_or_else(|| {
Partial::from_partial(PartialGlobalEdge::new(
Some(global_curve),
global_vertices,
))
});

Self {
vertices,
global_form,
}
}
}

impl PartialObject for PartialHalfEdge {
type Full = HalfEdge;

fn from_full(
half_edge: &Self::Full,
cache: &mut FullToPartialCache,
) -> Self {
Self::new(
half_edge
.vertices()
.clone()
.map(|vertex| Some(Partial::from_full(vertex, cache))),
Some(Partial::from_full(half_edge.global_form().clone(), cache)),
)
}

fn build(self, objects: &mut Service<Objects>) -> Self::Full {
let vertices = self.vertices.map(|vertex| vertex.build(objects));
let global_form = self.global_form.build(objects);

HalfEdge::new(vertices, global_form)
}
}

impl Default for PartialHalfEdge {
fn default() -> Self {
Self::new([None, None], None)
}
}

/// A partial [`GlobalEdge`]
#[derive(Clone, Debug)]
pub struct PartialGlobalEdge {
/// The curve that defines the edge's geometry
pub curve: Partial<GlobalCurve>,

/// The vertices that bound the edge on the curve
pub vertices: [Partial<GlobalVertex>; 2],
}

impl PartialGlobalEdge {
/// Construct an instance of `PartialGlobalEdge`
pub fn new(
curve: Option<Partial<GlobalCurve>>,
vertices: [Option<Partial<GlobalVertex>>; 2],
) -> Self {
let curve = curve.unwrap_or_default();
let vertices = vertices.map(Option::unwrap_or_default);

Self { curve, vertices }
}
}

impl PartialObject for PartialGlobalEdge {
type Full = GlobalEdge;

fn from_full(
global_edge: &Self::Full,
cache: &mut FullToPartialCache,
) -> Self {
Self::new(
Some(Partial::from_full(global_edge.curve().clone(), cache)),
global_edge
.vertices()
.access_in_normalized_order()
.map(|vertex| Some(Partial::from_full(vertex, cache))),
)
}

fn build(self, objects: &mut Service<Objects>) -> Self::Full {
let curve = self.curve.build(objects);
let vertices = self.vertices.map(|vertex| vertex.build(objects));

GlobalEdge::new(curve, vertices)
}
}

impl Default for PartialGlobalEdge {
fn default() -> Self {
Self::new(None, [None, None])
}
}
68 changes: 68 additions & 0 deletions crates/fj-kernel/src/partial2/objects/face.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use fj_interop::mesh::Color;

use crate::{
objects::{Cycle, Face, Objects},
partial2::{FullToPartialCache, Partial, PartialObject},
services::Service,
};

/// A partial [`Face`]
#[derive(Clone, Debug)]
pub struct PartialFace {
/// The cycle that bounds the face on the outside
pub exterior: Partial<Cycle>,

/// The cycles that bound the face on the inside
///
/// Each of these cycles defines a hole in the face.
pub interiors: Vec<Partial<Cycle>>,

/// The color of the face
pub color: Option<Color>,
}

impl PartialFace {
/// Construct an instance of `PartialFace`
pub fn new(
exterior: Option<Partial<Cycle>>,
interiors: Vec<Partial<Cycle>>,
color: Option<Color>,
) -> Self {
let exterior = exterior.unwrap_or_default();

Self {
exterior,
interiors,
color,
}
}
}

impl PartialObject for PartialFace {
type Full = Face;

fn from_full(face: &Self::Full, cache: &mut FullToPartialCache) -> Self {
Self::new(
Some(Partial::from_full(face.exterior().clone(), cache)),
face.interiors()
.map(|cycle| Partial::from_full(cycle.clone(), cache))
.collect(),
Some(face.color()),
)
}

fn build(self, objects: &mut Service<Objects>) -> Self::Full {
let exterior = self.exterior.build(objects);
let interiors =
self.interiors.into_iter().map(|cycle| cycle.build(objects));
let color = self.color.unwrap_or_default();

Face::new(exterior, interiors, color)
}
}

impl Default for PartialFace {
fn default() -> Self {
Self::new(None, Vec::new(), None)
}
}
Loading

0 comments on commit 045255a

Please sign in to comment.