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,
|
services::Services,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Sweep, SweepCache};
|
use super::{SweepCache, SweepHalfEdge};
|
||||||
|
|
||||||
impl Sweep for &Face {
|
/// # Sweep a [`Face`]
|
||||||
type Swept = Shell;
|
///
|
||||||
|
/// See [module documentation] for more information.
|
||||||
fn sweep_with_cache(
|
///
|
||||||
self,
|
/// [module documentation]: super
|
||||||
|
pub trait SweepFace {
|
||||||
|
/// # Sweep the [`Face`]
|
||||||
|
fn sweep_face(
|
||||||
|
&self,
|
||||||
path: impl Into<Vector<3>>,
|
path: impl Into<Vector<3>>,
|
||||||
cache: &mut SweepCache,
|
cache: &mut SweepCache,
|
||||||
services: &mut Services,
|
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
|
// Please note that this function uses the words "bottom" and "top" in a
|
||||||
// specific sense:
|
// specific sense:
|
||||||
//
|
//
|
||||||
|
@ -62,13 +75,14 @@ impl Sweep for &Face {
|
||||||
let (bottom_half_edge, bottom_half_edge_next) =
|
let (bottom_half_edge, bottom_half_edge_next) =
|
||||||
bottom_half_edge_pair;
|
bottom_half_edge_pair;
|
||||||
|
|
||||||
let (side_face, top_edge) = (
|
let (side_face, top_edge) = bottom_half_edge.sweep_half_edge(
|
||||||
bottom_half_edge.deref(),
|
|
||||||
bottom_half_edge_next.start_vertex().clone(),
|
bottom_half_edge_next.start_vertex().clone(),
|
||||||
bottom_face.surface().deref(),
|
bottom_face.surface().deref(),
|
||||||
bottom_face.region().color(),
|
bottom_face.region().color(),
|
||||||
)
|
path,
|
||||||
.sweep_with_cache(path, cache, services);
|
cache,
|
||||||
|
services,
|
||||||
|
);
|
||||||
|
|
||||||
let side_face = side_face.insert(services);
|
let side_face = side_face.insert(services);
|
||||||
|
|
||||||
|
|
|
@ -12,37 +12,66 @@ use crate::{
|
||||||
storage::Handle,
|
storage::Handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Sweep, SweepCache};
|
use super::{vertex::SweepVertex, SweepCache, SweepSurfacePath};
|
||||||
|
|
||||||
impl Sweep for (&HalfEdge, Handle<Vertex>, &Surface, Option<Color>) {
|
/// # Sweep a [`HalfEdge`]
|
||||||
type Swept = (Face, Handle<HalfEdge>);
|
///
|
||||||
|
/// See [module documentation] for more information.
|
||||||
fn sweep_with_cache(
|
///
|
||||||
self,
|
/// [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>>,
|
path: impl Into<Vector<3>>,
|
||||||
cache: &mut SweepCache,
|
cache: &mut SweepCache,
|
||||||
services: &mut Services,
|
services: &mut Services,
|
||||||
) -> Self::Swept {
|
) -> (Face, Handle<HalfEdge>);
|
||||||
let (edge, end_vertex, surface, color) = 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,
|
||||||
|
) -> (Face, Handle<HalfEdge>) {
|
||||||
let path = path.into();
|
let path = path.into();
|
||||||
|
|
||||||
let surface = (edge.path(), surface)
|
let surface = self
|
||||||
.sweep_with_cache(path, cache, services)
|
.path()
|
||||||
|
.sweep_surface_path(surface, path)
|
||||||
.insert(services);
|
.insert(services);
|
||||||
|
|
||||||
// Next, we need to define the boundaries of the face. Let's start with
|
// Next, we need to define the boundaries of the face. Let's start with
|
||||||
// the global vertices and edges.
|
// the global vertices and edges.
|
||||||
let (vertices, curves) = {
|
let (vertices, curves) = {
|
||||||
let [a, b] = [edge.start_vertex().clone(), end_vertex];
|
let [a, b] = [self.start_vertex().clone(), end_vertex];
|
||||||
let (curve_up, c) =
|
let (curve_up, c) = b.clone().sweep_vertex(cache, services);
|
||||||
b.clone().sweep_with_cache(path, cache, services);
|
let (curve_down, d) = a.clone().sweep_vertex(cache, services);
|
||||||
let (curve_down, d) =
|
|
||||||
a.clone().sweep_with_cache(path, cache, services);
|
|
||||||
|
|
||||||
(
|
(
|
||||||
[a, b, c, d],
|
[a, b, c, d],
|
||||||
[
|
[
|
||||||
Some(edge.curve().clone()),
|
Some(self.curve().clone()),
|
||||||
Some(curve_up),
|
Some(curve_up),
|
||||||
None,
|
None,
|
||||||
Some(curve_down),
|
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's figure out the surface coordinates of the edge vertices.
|
||||||
let surface_points = {
|
let surface_points = {
|
||||||
let [a, b] = edge.boundary().inner;
|
let [a, b] = self.boundary().inner;
|
||||||
|
|
||||||
[
|
[
|
||||||
[a.t, Scalar::ZERO],
|
[a.t, Scalar::ZERO],
|
||||||
|
@ -70,7 +99,7 @@ impl Sweep for (&HalfEdge, Handle<Vertex>, &Surface, Option<Color>) {
|
||||||
|
|
||||||
// Now, the boundaries of each edge.
|
// Now, the boundaries of each edge.
|
||||||
let boundaries = {
|
let boundaries = {
|
||||||
let [a, b] = edge.boundary().inner;
|
let [a, b] = self.boundary().inner;
|
||||||
let [c, d] = [0., 1.].map(|coord| Point::from([coord]));
|
let [c, d] = [0., 1.].map(|coord| Point::from([coord]));
|
||||||
|
|
||||||
[[a, b], [c, d], [b, a], [d, c]]
|
[[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 face;
|
||||||
mod half_edge;
|
mod half_edge;
|
||||||
|
@ -6,43 +9,19 @@ mod path;
|
||||||
mod sketch;
|
mod sketch;
|
||||||
mod vertex;
|
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::{
|
use crate::{
|
||||||
objects::{Curve, Vertex},
|
objects::{Curve, Vertex},
|
||||||
services::Services,
|
|
||||||
storage::{Handle, ObjectId},
|
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
|
/// A cache used for sweeping
|
||||||
///
|
|
||||||
/// See [`Sweep`].
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct SweepCache {
|
pub struct SweepCache {
|
||||||
/// Cache for curves
|
/// Cache for curves
|
||||||
|
|
|
@ -3,22 +3,37 @@ use fj_math::{Circle, Line, Vector};
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{GlobalPath, SurfaceGeometry, SurfacePath},
|
geometry::{GlobalPath, SurfaceGeometry, SurfacePath},
|
||||||
objects::Surface,
|
objects::Surface,
|
||||||
services::Services,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Sweep, SweepCache};
|
/// # Sweep a [`SurfacePath`]
|
||||||
|
///
|
||||||
impl Sweep for (SurfacePath, &Surface) {
|
/// See [module documentation] for more information.
|
||||||
type Swept = Surface;
|
///
|
||||||
|
/// [module documentation]: super
|
||||||
fn sweep_with_cache(
|
pub trait SweepSurfacePath {
|
||||||
self,
|
/// # 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>>,
|
path: impl Into<Vector<3>>,
|
||||||
_: &mut SweepCache,
|
) -> Surface;
|
||||||
_: &mut Services,
|
}
|
||||||
) -> Self::Swept {
|
|
||||||
let (curve, surface) = self;
|
|
||||||
|
|
||||||
|
impl SweepSurfacePath for SurfacePath {
|
||||||
|
fn sweep_surface_path(
|
||||||
|
&self,
|
||||||
|
surface: &Surface,
|
||||||
|
path: impl Into<Vector<3>>,
|
||||||
|
) -> Surface {
|
||||||
match surface.geometry().u {
|
match surface.geometry().u {
|
||||||
GlobalPath::Circle(_) => {
|
GlobalPath::Circle(_) => {
|
||||||
// Sweeping a `Curve` creates a `Surface`. The u-axis of that
|
// 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) => {
|
SurfacePath::Circle(circle) => {
|
||||||
let center = surface
|
let center = surface
|
||||||
.geometry()
|
.geometry()
|
||||||
|
|
|
@ -7,27 +7,39 @@ use crate::{
|
||||||
storage::Handle,
|
storage::Handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Sweep, SweepCache};
|
use super::{face::SweepFace, SweepCache};
|
||||||
|
|
||||||
impl Sweep for (&Sketch, Handle<Surface>) {
|
/// # Sweep a [`Sketch`]
|
||||||
type Swept = Solid;
|
///
|
||||||
|
/// See [module documentation] for more information.
|
||||||
fn sweep_with_cache(
|
///
|
||||||
self,
|
/// [module documentation]: super
|
||||||
|
pub trait SweepSketch {
|
||||||
|
/// # Sweep the [`Sketch`]
|
||||||
|
fn sweep_sketch(
|
||||||
|
&self,
|
||||||
|
surface: Handle<Surface>,
|
||||||
path: impl Into<Vector<3>>,
|
path: impl Into<Vector<3>>,
|
||||||
cache: &mut SweepCache,
|
|
||||||
services: &mut Services,
|
services: &mut Services,
|
||||||
) -> Self::Swept {
|
) -> Solid;
|
||||||
let (sketch, surface) = self;
|
}
|
||||||
|
|
||||||
|
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 path = path.into();
|
||||||
|
let mut cache = SweepCache::default();
|
||||||
|
|
||||||
let mut shells = Vec::new();
|
let mut shells = Vec::new();
|
||||||
for region in sketch.regions() {
|
for region in self.regions() {
|
||||||
let face =
|
let face =
|
||||||
Face::new(surface.clone(), region.clone()).insert(services);
|
Face::new(surface.clone(), region.clone()).insert(services);
|
||||||
let shell = face
|
let shell =
|
||||||
.sweep_with_cache(path, cache, services)
|
face.sweep_face(path, &mut cache, services).insert(services);
|
||||||
.insert(services);
|
|
||||||
shells.push(shell);
|
shells.push(shell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use fj_math::Vector;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{Curve, Vertex},
|
objects::{Curve, Vertex},
|
||||||
operations::insert::Insert,
|
operations::insert::Insert,
|
||||||
|
@ -7,17 +5,45 @@ use crate::{
|
||||||
storage::Handle,
|
storage::Handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Sweep, SweepCache};
|
use super::SweepCache;
|
||||||
|
|
||||||
impl Sweep for Handle<Vertex> {
|
/// # Sweep a [`Vertex`]
|
||||||
type Swept = (Handle<Curve>, Self);
|
///
|
||||||
|
/// See [module documentation] for more information.
|
||||||
fn sweep_with_cache(
|
///
|
||||||
self,
|
/// [module documentation]: super
|
||||||
_: impl Into<Vector<3>>,
|
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,
|
cache: &mut SweepCache,
|
||||||
services: &mut Services,
|
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
|
let curve = cache
|
||||||
.curves
|
.curves
|
||||||
.entry(self.id())
|
.entry(self.id())
|
||||||
|
|
|
@ -4,7 +4,7 @@ use fj::{
|
||||||
operations::{
|
operations::{
|
||||||
build::{BuildRegion, BuildSketch},
|
build::{BuildRegion, BuildSketch},
|
||||||
insert::Insert,
|
insert::Insert,
|
||||||
sweep::Sweep,
|
sweep::SweepSketch,
|
||||||
update::UpdateSketch,
|
update::UpdateSketch,
|
||||||
},
|
},
|
||||||
services::Services,
|
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 surface = services.objects.surfaces.xy_plane();
|
||||||
let path = Vector::from([0., 0., z]);
|
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},
|
build::{BuildCycle, BuildRegion, BuildSketch},
|
||||||
insert::Insert,
|
insert::Insert,
|
||||||
reverse::Reverse,
|
reverse::Reverse,
|
||||||
sweep::Sweep,
|
sweep::SweepSketch,
|
||||||
update::{UpdateRegion, UpdateSketch},
|
update::{UpdateRegion, UpdateSketch},
|
||||||
},
|
},
|
||||||
services::Services,
|
services::Services,
|
||||||
|
@ -30,5 +30,7 @@ pub fn model(
|
||||||
|
|
||||||
let surface = services.objects.surfaces.xy_plane();
|
let surface = services.objects.surfaces.xy_plane();
|
||||||
let path = Vector::from([0., 0., height]);
|
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},
|
build::{BuildRegion, BuildSketch},
|
||||||
insert::Insert,
|
insert::Insert,
|
||||||
split::SplitFace,
|
split::SplitFace,
|
||||||
sweep::Sweep,
|
sweep::SweepSketch,
|
||||||
update::{UpdateSketch, UpdateSolid},
|
update::{UpdateSketch, UpdateSolid},
|
||||||
},
|
},
|
||||||
services::Services,
|
services::Services,
|
||||||
|
@ -34,7 +34,7 @@ pub fn model(
|
||||||
|
|
||||||
let surface = services.objects.surfaces.xy_plane();
|
let surface = services.objects.surfaces.xy_plane();
|
||||||
let path = Vector::from([0., 0., size]);
|
let path = Vector::from([0., 0., size]);
|
||||||
let solid = (&sketch, surface).sweep(path, services);
|
let solid = sketch.sweep_sketch(surface, path, services);
|
||||||
|
|
||||||
solid
|
solid
|
||||||
.update_shell(solid.shells().only(), |shell| {
|
.update_shell(solid.shells().only(), |shell| {
|
||||||
|
|
|
@ -7,7 +7,7 @@ use fj::{
|
||||||
build::{BuildCycle, BuildRegion, BuildSketch},
|
build::{BuildCycle, BuildRegion, BuildSketch},
|
||||||
insert::Insert,
|
insert::Insert,
|
||||||
reverse::Reverse,
|
reverse::Reverse,
|
||||||
sweep::Sweep,
|
sweep::SweepSketch,
|
||||||
update::{UpdateRegion, UpdateSketch},
|
update::{UpdateRegion, UpdateSketch},
|
||||||
},
|
},
|
||||||
services::Services,
|
services::Services,
|
||||||
|
@ -53,5 +53,7 @@ pub fn model(
|
||||||
|
|
||||||
let surface = services.objects.surfaces.xy_plane();
|
let surface = services.objects.surfaces.xy_plane();
|
||||||
let path = Vector::from([0., 0., h]);
|
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