Skip to content

Commit

Permalink
Merge pull request #2111 from hannobraun/sweep
Browse files Browse the repository at this point in the history
Extract `SweepRegion` from `SweepFace`
  • Loading branch information
hannobraun authored Nov 24, 2023
2 parents 899f5a9 + 787cd7f commit 0b33079
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 61 deletions.
4 changes: 2 additions & 2 deletions crates/fj-core/src/operations/sweep/cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ impl SweepCycle for Cycle {
}
}

/// The result of sweeping a cycle
/// The result of sweeping a [`Cycle`]
///
/// See [`SweepCycle`].
pub struct SweptCycle {
Expand All @@ -96,7 +96,7 @@ pub struct SweptCycle {
/// See [`SweepCycle::sweep_cycle`] for more information.
pub faces: Vec<Face>,

/// A cycle mad up of the "top" half-edges of the resulting faces
/// A cycle made up of the "top" half-edges of the resulting faces
///
/// "Top" here refers to the place that the sweep path points to from the
/// original cycle. Essentially, this is a translated (along the sweep path)
Expand Down
76 changes: 17 additions & 59 deletions crates/fj-core/src/operations/sweep/face.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ use fj_math::{Scalar, Vector};
use crate::{
algorithms::transform::TransformObject,
geometry::GlobalPath,
objects::{Cycle, Face, Region, Shell},
objects::{Face, Shell},
operations::{insert::Insert, reverse::Reverse},
services::Services,
storage::Handle,
};

use super::{SweepCache, SweepCycle};
use super::{SweepCache, SweepRegion};

/// # Sweep a [`Face`]
///
Expand Down Expand Up @@ -53,41 +52,26 @@ impl SweepFace for Face {
let bottom_face = bottom_face(self, path, services).insert(services);
faces.push(bottom_face.clone());

let top_surface =
bottom_face.surface().clone().translate(path, services);

let top_exterior = sweep_cycle(
bottom_face.region().exterior(),
&bottom_face,
&mut faces,
let swept_region = bottom_face.region().sweep_region(
bottom_face.surface(),
path,
cache,
services,
);

let mut top_interiors = Vec::new();

for bottom_cycle in bottom_face.region().interiors() {
let top_cycle = sweep_cycle(
bottom_cycle,
&bottom_face,
&mut faces,
path,
cache,
services,
);

top_interiors.push(top_cycle);
}

let top_region = Region::new(
top_exterior,
top_interiors,
bottom_face.region().color(),
)
.insert(services);

let top_face = Face::new(top_surface, top_region).insert(services);
let side_faces = swept_region
.faces
.into_iter()
.map(|side_face| side_face.insert(services));
faces.extend(side_faces);

let top_face = {
let top_surface =
bottom_face.surface().clone().translate(path, services);
let top_region = swept_region.top_region.insert(services);

Face::new(top_surface, top_region).insert(services)
};
faces.push(top_face);

Shell::new(faces)
Expand Down Expand Up @@ -116,29 +100,3 @@ fn bottom_face(face: &Face, path: Vector<3>, services: &mut Services) -> Face {
face.reverse(services)
}
}

fn sweep_cycle(
bottom_cycle: &Cycle,
bottom_face: &Face,
faces: &mut Vec<Handle<Face>>,
path: Vector<3>,
cache: &mut SweepCache,
services: &mut Services,
) -> Handle<Cycle> {
let swept_cycle = bottom_cycle.reverse(services).sweep_cycle(
bottom_face.surface(),
bottom_face.region().color(),
path,
cache,
services,
);

faces.extend(
swept_cycle
.faces
.into_iter()
.map(|side_face| side_face.insert(services)),
);

swept_cycle.top_cycle.insert(services)
}
2 changes: 2 additions & 0 deletions crates/fj-core/src/operations/sweep/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod cycle;
mod face;
mod half_edge;
mod path;
mod region;
mod sketch;
mod vertex;

Expand All @@ -15,6 +16,7 @@ pub use self::{
face::SweepFace,
half_edge::SweepHalfEdge,
path::SweepSurfacePath,
region::{SweepRegion, SweptRegion},
sketch::SweepSketch,
vertex::SweepVertex,
};
Expand Down
126 changes: 126 additions & 0 deletions crates/fj-core/src/operations/sweep/region.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use fj_interop::mesh::Color;
use fj_math::Vector;

use crate::{
objects::{Cycle, Face, Region, Surface},
operations::{insert::Insert, reverse::Reverse},
services::Services,
storage::Handle,
};

use super::{SweepCache, SweepCycle};

/// # Sweep a [`Region`]
///
/// See [module documentation] for more information.
///
/// [module documentation]: super
pub trait SweepRegion {
/// # Sweep the [`Region`]
///
/// Sweep the region into multiple sets of faces. Each set of faces is
/// formed by sweeping one of the region's cycles
///
/// Requires the surface that the face that the region belongs to is defined
/// in.
///
/// There are no faces at the "top" (the end of the sweep path) or "bottom".
///
/// There is no face at the "top" (the end of the sweep path). We *would*
/// have enough information to create that, as we have access to the surface
/// too and could translate that here. However, that we have access to that
/// surface is a bit incidental, and a weird artifact of how the object
/// graph currently works. For this reason, the creating the top face is
/// considered out of scope for this operation, and left to the caller.
///
/// There also is no "bottom" face. Whether having one is desirable, depends
/// on the context of the caller of this operation, and there also falls
/// outside of its scope.
fn sweep_region(
&self,
surface: &Surface,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
services: &mut Services,
) -> SweptRegion;
}

impl SweepRegion for Region {
fn sweep_region(
&self,
surface: &Surface,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
services: &mut Services,
) -> SweptRegion {
let path = path.into();

let mut faces = Vec::new();

let top_exterior = sweep_cycle(
self.exterior(),
surface,
self.color(),
&mut faces,
path,
cache,
services,
);

let mut top_interiors = Vec::new();

for bottom_cycle in self.interiors() {
let top_cycle = sweep_cycle(
bottom_cycle,
surface,
self.color(),
&mut faces,
path,
cache,
services,
);

top_interiors.push(top_cycle);
}

let top_region = Region::new(top_exterior, top_interiors, self.color());

SweptRegion { faces, top_region }
}
}

/// The result of sweeping a [`Region`]
///
/// See [`SweepRegion`].
pub struct SweptRegion {
/// The faces created by sweeping each cycle of the region
pub faces: Vec<Face>,

/// A region made up of the "top" cycles
///
/// This is essentially a version of the original region, translated by the
/// sweep path.
pub top_region: Region,
}

fn sweep_cycle(
bottom_cycle: &Cycle,
bottom_surface: &Surface,
color: Option<Color>,
faces: &mut Vec<Face>,
path: Vector<3>,
cache: &mut SweepCache,
services: &mut Services,
) -> Handle<Cycle> {
let swept_cycle = bottom_cycle.reverse(services).sweep_cycle(
bottom_surface,
color,
path,
cache,
services,
);

faces.extend(swept_cycle.faces);

swept_cycle.top_cycle.insert(services)
}

0 comments on commit 0b33079

Please sign in to comment.