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

Introduce new partial object API #1428

Merged
merged 18 commits into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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