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

Replace Sweep with object-specific traits #2106

Merged
merged 7 commits into from
Nov 23, 2023
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
36 changes: 25 additions & 11 deletions crates/fj-core/src/operations/sweep/face.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,30 @@ use crate::{
services::Services,
};

use super::{Sweep, SweepCache};

impl Sweep for &Face {
type Swept = Shell;
use super::{SweepCache, SweepHalfEdge};

/// # Sweep a [`Face`]
///
/// See [module documentation] for more information.
///
/// [module documentation]: super
pub trait SweepFace {
/// # Sweep the [`Face`]
fn sweep_face(
&self,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
services: &mut Services,
) -> Shell;
}

fn sweep_with_cache(
self,
impl SweepFace for Face {
fn sweep_face(
&self,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
services: &mut Services,
) -> Self::Swept {
) -> Shell {
// Please note that this function uses the words "bottom" and "top" in a
// specific sense:
//
Expand Down Expand Up @@ -62,13 +75,14 @@ impl Sweep for &Face {
let (bottom_half_edge, bottom_half_edge_next) =
bottom_half_edge_pair;

let (side_face, top_edge) = (
bottom_half_edge.deref(),
let (side_face, top_edge) = bottom_half_edge.sweep_half_edge(
bottom_half_edge_next.start_vertex().clone(),
bottom_face.surface().deref(),
bottom_face.region().color(),
)
.sweep_with_cache(path, cache, services);
path,
cache,
services,
);

let side_face = side_face.insert(services);

Expand Down
65 changes: 47 additions & 18 deletions crates/fj-core/src/operations/sweep/half_edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,66 @@ use crate::{
storage::Handle,
};

use super::{Sweep, SweepCache};

impl Sweep for (&HalfEdge, Handle<Vertex>, &Surface, Option<Color>) {
type Swept = (Face, Handle<HalfEdge>);
use super::{vertex::SweepVertex, SweepCache, SweepSurfacePath};

/// # Sweep a [`HalfEdge`]
///
/// See [module documentation] for more information.
///
/// [module documentation]: super
pub trait SweepHalfEdge {
/// # Sweep the [`HalfEdge`]
///
/// Returns a face, the result of sweeping the edge, as well as the top edge
/// of that face, i.e. the edge that is the version of the original edge
/// that was translated along the sweep path.
///
/// In addition to the usual arguments that many sweep operations require,
/// some other ones are needed:
///
/// - `end_vertex`, the vertex where the half-edge ends. This is the start
/// vertex of the next half-edge in the cycle.
/// - The `surface` that the half-edge is defined on.
/// - The `color` of the resulting face, if applicable
fn sweep_half_edge(
&self,
end_vertex: Handle<Vertex>,
surface: &Surface,
color: Option<Color>,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
services: &mut Services,
) -> (Face, Handle<HalfEdge>);
}

fn sweep_with_cache(
self,
impl SweepHalfEdge for HalfEdge {
fn sweep_half_edge(
&self,
end_vertex: Handle<Vertex>,
surface: &Surface,
color: Option<Color>,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
services: &mut Services,
) -> Self::Swept {
let (edge, end_vertex, surface, color) = self;
) -> (Face, Handle<HalfEdge>) {
let path = path.into();

let surface = (edge.path(), surface)
.sweep_with_cache(path, cache, services)
let surface = self
.path()
.sweep_surface_path(surface, path)
.insert(services);

// Next, we need to define the boundaries of the face. Let's start with
// the global vertices and edges.
let (vertices, curves) = {
let [a, b] = [edge.start_vertex().clone(), end_vertex];
let (curve_up, c) =
b.clone().sweep_with_cache(path, cache, services);
let (curve_down, d) =
a.clone().sweep_with_cache(path, cache, services);
let [a, b] = [self.start_vertex().clone(), end_vertex];
let (curve_up, c) = b.clone().sweep_vertex(cache, services);
let (curve_down, d) = a.clone().sweep_vertex(cache, services);

(
[a, b, c, d],
[
Some(edge.curve().clone()),
Some(self.curve().clone()),
Some(curve_up),
None,
Some(curve_down),
Expand All @@ -52,7 +81,7 @@ impl Sweep for (&HalfEdge, Handle<Vertex>, &Surface, Option<Color>) {

// Let's figure out the surface coordinates of the edge vertices.
let surface_points = {
let [a, b] = edge.boundary().inner;
let [a, b] = self.boundary().inner;

[
[a.t, Scalar::ZERO],
Expand All @@ -70,7 +99,7 @@ impl Sweep for (&HalfEdge, Handle<Vertex>, &Surface, Option<Color>) {

// Now, the boundaries of each edge.
let boundaries = {
let [a, b] = edge.boundary().inner;
let [a, b] = self.boundary().inner;
let [c, d] = [0., 1.].map(|coord| Point::from([coord]));

[[a, b], [c, d], [b, a], [d, c]]
Expand Down
39 changes: 9 additions & 30 deletions crates/fj-core/src/operations/sweep/mod.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,27 @@
//! Sweeping objects along a path to create new objects
//! Sweep objects along a path to create new objects
//!
//! Sweeps 1D or 2D objects along a straight path, creating a 2D or 3D object,
//! respectively.

mod face;
mod half_edge;
mod path;
mod sketch;
mod vertex;

use std::collections::BTreeMap;
pub use self::{
face::SweepFace, half_edge::SweepHalfEdge, path::SweepSurfacePath,
sketch::SweepSketch, vertex::SweepVertex,
};

use fj_math::Vector;
use std::collections::BTreeMap;

use crate::{
objects::{Curve, Vertex},
services::Services,
storage::{Handle, ObjectId},
};

/// Sweep an object along a path to create another object
pub trait Sweep: Sized {
/// The object that is created by sweeping the implementing object
type Swept;

/// Sweep the object along the given path
fn sweep(
self,
path: impl Into<Vector<3>>,
services: &mut Services,
) -> Self::Swept {
let mut cache = SweepCache::default();
self.sweep_with_cache(path, &mut cache, services)
}

/// Sweep the object along the given path, using the provided cache
fn sweep_with_cache(
self,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
services: &mut Services,
) -> Self::Swept;
}

/// A cache used for sweeping
///
/// See [`Sweep`].
#[derive(Default)]
pub struct SweepCache {
/// Cache for curves
Expand Down
41 changes: 28 additions & 13 deletions crates/fj-core/src/operations/sweep/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,37 @@ use fj_math::{Circle, Line, Vector};
use crate::{
geometry::{GlobalPath, SurfaceGeometry, SurfacePath},
objects::Surface,
services::Services,
};

use super::{Sweep, SweepCache};

impl Sweep for (SurfacePath, &Surface) {
type Swept = Surface;

fn sweep_with_cache(
self,
/// # Sweep a [`SurfacePath`]
///
/// See [module documentation] for more information.
///
/// [module documentation]: super
pub trait SweepSurfacePath {
/// # Sweep the surface path
///
/// Requires a reference to the surface that the path is defined on.
///
///
/// ## Implementation Note
///
/// Sweeping a `SurfacePath` that is defined on a curved surface is
/// currently not supported:
/// <https://github.com/hannobraun/fornjot/issues/1112>
fn sweep_surface_path(
&self,
surface: &Surface,
path: impl Into<Vector<3>>,
_: &mut SweepCache,
_: &mut Services,
) -> Self::Swept {
let (curve, surface) = self;
) -> Surface;
}

impl SweepSurfacePath for SurfacePath {
fn sweep_surface_path(
&self,
surface: &Surface,
path: impl Into<Vector<3>>,
) -> Surface {
match surface.geometry().u {
GlobalPath::Circle(_) => {
// Sweeping a `Curve` creates a `Surface`. The u-axis of that
Expand All @@ -43,7 +58,7 @@ impl Sweep for (SurfacePath, &Surface) {
}
}

let u = match curve {
let u = match self {
SurfacePath::Circle(circle) => {
let center = surface
.geometry()
Expand Down
36 changes: 24 additions & 12 deletions crates/fj-core/src/operations/sweep/sketch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,39 @@ use crate::{
storage::Handle,
};

use super::{Sweep, SweepCache};
use super::{face::SweepFace, SweepCache};

impl Sweep for (&Sketch, Handle<Surface>) {
type Swept = Solid;
/// # Sweep a [`Sketch`]
///
/// See [module documentation] for more information.
///
/// [module documentation]: super
pub trait SweepSketch {
/// # Sweep the [`Sketch`]
fn sweep_sketch(
&self,
surface: Handle<Surface>,
path: impl Into<Vector<3>>,
services: &mut Services,
) -> Solid;
}

fn sweep_with_cache(
self,
impl SweepSketch for Sketch {
fn sweep_sketch(
&self,
surface: Handle<Surface>,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
services: &mut Services,
) -> Self::Swept {
let (sketch, surface) = self;
) -> Solid {
let path = path.into();
let mut cache = SweepCache::default();

let mut shells = Vec::new();
for region in sketch.regions() {
for region in self.regions() {
let face =
Face::new(surface.clone(), region.clone()).insert(services);
let shell = face
.sweep_with_cache(path, cache, services)
.insert(services);
let shell =
face.sweep_face(path, &mut cache, services).insert(services);
shells.push(shell);
}

Expand Down
44 changes: 35 additions & 9 deletions crates/fj-core/src/operations/sweep/vertex.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,49 @@
use fj_math::Vector;

use crate::{
objects::{Curve, Vertex},
operations::insert::Insert,
services::Services,
storage::Handle,
};

use super::{Sweep, SweepCache};
use super::SweepCache;

impl Sweep for Handle<Vertex> {
type Swept = (Handle<Curve>, Self);
/// # Sweep a [`Vertex`]
///
/// See [module documentation] for more information.
///
/// [module documentation]: super
pub trait SweepVertex: Sized {
/// # Sweep the vertex
///
/// Returns the curve that the vertex was swept along, as well as a new
/// vertex to represent the point at the end of the sweep.
///
///
/// ## Comparison to Other Sweep Operations
///
/// This method is a bit weird, compared to most other sweep operations, in
/// that it doesn't actually do any sweeping. That is because because both
/// [`Vertex`] and [`Curve`] do not define any geometry (please refer to
/// their respective documentation). Because of that, this method doesn't
/// even take the sweep path as an argument.
///
/// The reason this code still exists as part of the sweep infrastructure,
/// is to make sure that sweeping the same vertex multiple times always
/// results in the same curve. This is also the reason that this trait is
/// only implemented for `Handle<Vertex>` and produces a `Handle<Curve>`.
fn sweep_vertex(
&self,
cache: &mut SweepCache,
services: &mut Services,
) -> (Handle<Curve>, Handle<Vertex>);
}

fn sweep_with_cache(
self,
_: impl Into<Vector<3>>,
impl SweepVertex for Handle<Vertex> {
fn sweep_vertex(
&self,
cache: &mut SweepCache,
services: &mut Services,
) -> Self::Swept {
) -> (Handle<Curve>, Handle<Vertex>) {
let curve = cache
.curves
.entry(self.id())
Expand Down
Loading