mirror of https://github.com/hannobraun/Fornjot
Merge pull request #2106 from hannobraun/sweep
Replace `Sweep` with object-specific traits
This commit is contained in:
commit
71888c76aa
|
@ -12,17 +12,30 @@ use crate::{
|
|||
services::Services,
|
||||
};
|
||||
|
||||
use super::{Sweep, SweepCache};
|
||||
use super::{SweepCache, SweepHalfEdge};
|
||||
|
||||
impl Sweep for &Face {
|
||||
type Swept = Shell;
|
||||
|
||||
fn sweep_with_cache(
|
||||
self,
|
||||
/// # 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,
|
||||
) -> Self::Swept {
|
||||
) -> Shell;
|
||||
}
|
||||
|
||||
impl SweepFace for Face {
|
||||
fn sweep_face(
|
||||
&self,
|
||||
path: impl Into<Vector<3>>,
|
||||
cache: &mut SweepCache,
|
||||
services: &mut Services,
|
||||
) -> Shell {
|
||||
// Please note that this function uses the words "bottom" and "top" in a
|
||||
// specific sense:
|
||||
//
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -12,37 +12,66 @@ use crate::{
|
|||
storage::Handle,
|
||||
};
|
||||
|
||||
use super::{Sweep, SweepCache};
|
||||
use super::{vertex::SweepVertex, SweepCache, SweepSurfacePath};
|
||||
|
||||
impl Sweep for (&HalfEdge, Handle<Vertex>, &Surface, Option<Color>) {
|
||||
type Swept = (Face, Handle<HalfEdge>);
|
||||
|
||||
fn sweep_with_cache(
|
||||
self,
|
||||
/// # 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,
|
||||
) -> Self::Swept {
|
||||
let (edge, end_vertex, surface, color) = self;
|
||||
) -> (Face, Handle<HalfEdge>);
|
||||
}
|
||||
|
||||
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,
|
||||
) -> (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),
|
||||
|
@ -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],
|
||||
|
@ -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]]
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
//! 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;
|
||||
|
@ -6,43 +9,19 @@ 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
|
||||
|
|
|
@ -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
|
||||
|
@ -43,7 +58,7 @@ impl Sweep for (SurfacePath, &Surface) {
|
|||
}
|
||||
}
|
||||
|
||||
let u = match curve {
|
||||
let u = match self {
|
||||
SurfacePath::Circle(circle) => {
|
||||
let center = surface
|
||||
.geometry()
|
||||
|
|
|
@ -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;
|
||||
|
||||
fn sweep_with_cache(
|
||||
self,
|
||||
/// # 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>>,
|
||||
cache: &mut SweepCache,
|
||||
services: &mut Services,
|
||||
) -> Self::Swept {
|
||||
let (sketch, surface) = self;
|
||||
) -> Solid;
|
||||
}
|
||||
|
||||
impl SweepSketch for Sketch {
|
||||
fn sweep_sketch(
|
||||
&self,
|
||||
surface: Handle<Surface>,
|
||||
path: impl Into<Vector<3>>,
|
||||
services: &mut Services,
|
||||
) -> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use fj_math::Vector;
|
||||
|
||||
use crate::{
|
||||
objects::{Curve, Vertex},
|
||||
operations::insert::Insert,
|
||||
|
@ -7,17 +5,45 @@ use crate::{
|
|||
storage::Handle,
|
||||
};
|
||||
|
||||
use super::{Sweep, SweepCache};
|
||||
use super::SweepCache;
|
||||
|
||||
impl Sweep for Handle<Vertex> {
|
||||
type Swept = (Handle<Curve>, Self);
|
||||
|
||||
fn sweep_with_cache(
|
||||
self,
|
||||
_: impl Into<Vector<3>>,
|
||||
/// # 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,
|
||||
) -> Self::Swept {
|
||||
) -> (Handle<Curve>, Handle<Vertex>);
|
||||
}
|
||||
|
||||
impl SweepVertex for Handle<Vertex> {
|
||||
fn sweep_vertex(
|
||||
&self,
|
||||
cache: &mut SweepCache,
|
||||
services: &mut Services,
|
||||
) -> (Handle<Curve>, Handle<Vertex>) {
|
||||
let curve = cache
|
||||
.curves
|
||||
.entry(self.id())
|
||||
|
|
|
@ -4,7 +4,7 @@ use fj::{
|
|||
operations::{
|
||||
build::{BuildRegion, BuildSketch},
|
||||
insert::Insert,
|
||||
sweep::Sweep,
|
||||
sweep::SweepSketch,
|
||||
update::UpdateSketch,
|
||||
},
|
||||
services::Services,
|
||||
|
@ -29,5 +29,7 @@ pub fn model(x: f64, y: f64, z: f64, services: &mut Services) -> Handle<Solid> {
|
|||
|
||||
let surface = services.objects.surfaces.xy_plane();
|
||||
let path = Vector::from([0., 0., z]);
|
||||
(&sketch, surface).sweep(path, services).insert(services)
|
||||
sketch
|
||||
.sweep_sketch(surface, path, services)
|
||||
.insert(services)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use fj::{
|
|||
build::{BuildCycle, BuildRegion, BuildSketch},
|
||||
insert::Insert,
|
||||
reverse::Reverse,
|
||||
sweep::Sweep,
|
||||
sweep::SweepSketch,
|
||||
update::{UpdateRegion, UpdateSketch},
|
||||
},
|
||||
services::Services,
|
||||
|
@ -30,5 +30,7 @@ pub fn model(
|
|||
|
||||
let surface = services.objects.surfaces.xy_plane();
|
||||
let path = Vector::from([0., 0., height]);
|
||||
(&sketch, surface).sweep(path, services).insert(services)
|
||||
sketch
|
||||
.sweep_sketch(surface, path, services)
|
||||
.insert(services)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use fj::{
|
|||
build::{BuildRegion, BuildSketch},
|
||||
insert::Insert,
|
||||
split::SplitFace,
|
||||
sweep::Sweep,
|
||||
sweep::SweepSketch,
|
||||
update::{UpdateSketch, UpdateSolid},
|
||||
},
|
||||
services::Services,
|
||||
|
@ -34,7 +34,7 @@ pub fn model(
|
|||
|
||||
let surface = services.objects.surfaces.xy_plane();
|
||||
let path = Vector::from([0., 0., size]);
|
||||
let solid = (&sketch, surface).sweep(path, services);
|
||||
let solid = sketch.sweep_sketch(surface, path, services);
|
||||
|
||||
solid
|
||||
.update_shell(solid.shells().only(), |shell| {
|
||||
|
|
|
@ -7,7 +7,7 @@ use fj::{
|
|||
build::{BuildCycle, BuildRegion, BuildSketch},
|
||||
insert::Insert,
|
||||
reverse::Reverse,
|
||||
sweep::Sweep,
|
||||
sweep::SweepSketch,
|
||||
update::{UpdateRegion, UpdateSketch},
|
||||
},
|
||||
services::Services,
|
||||
|
@ -53,5 +53,7 @@ pub fn model(
|
|||
|
||||
let surface = services.objects.surfaces.xy_plane();
|
||||
let path = Vector::from([0., 0., h]);
|
||||
(&sketch, surface).sweep(path, services).insert(services)
|
||||
sketch
|
||||
.sweep_sketch(surface, path, services)
|
||||
.insert(services)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue