1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
use fj_interop::mesh::Color;
use fj_math::Vector;
use crate::{
objects::{Cycle, Face, Surface},
operations::{
build::BuildCycle, join::JoinCycle, sweep::half_edge::SweepHalfEdge,
},
services::Services,
};
use super::SweepCache;
/// # Sweep a [`Cycle`]
///
/// See [module documentation] for more information.
///
/// [module documentation]: super
pub trait SweepCycle {
/// # Sweep the [`Cycle`]
///
/// Sweep the cycle into a set of connected faces. Each half-edge in the
/// cycle is swept into a face, meaning all resulting faces form a connected
/// set of side walls.
///
/// Requires the surface that the half-edges of the cycle are defined in,
/// and optionally the color of the created faces.
///
/// There is no face at the "top" (the end of the sweep path), as we don't
/// have enough information here to create that. We just have a single
/// cycle, and don't know whether that is supposed to be the only cycle
/// within a potential top face, or whether it's an exterior or interior
/// one.
///
/// For the same reason, there also is no "bottom" face. Additionally,
/// whether a bottom face is even desirable depends on the context this
/// operation is called in, and therefore falls outside of its scope.
fn sweep_cycle(
&self,
surface: &Surface,
color: Option<Color>,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
services: &mut Services,
) -> SweptCycle;
}
impl SweepCycle for Cycle {
fn sweep_cycle(
&self,
surface: &Surface,
color: Option<Color>,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
services: &mut Services,
) -> SweptCycle {
let path = path.into();
let mut faces = Vec::new();
let mut top_edges = Vec::new();
for bottom_half_edge_pair in self.half_edges().pairs() {
let (bottom_half_edge, bottom_half_edge_next) =
bottom_half_edge_pair;
let (side_face, top_edge) = bottom_half_edge.sweep_half_edge(
bottom_half_edge_next.start_vertex().clone(),
surface,
color,
path,
cache,
services,
);
faces.push(side_face);
top_edges.push((
top_edge,
bottom_half_edge.path(),
bottom_half_edge.boundary(),
));
}
let top_cycle = Cycle::empty().add_joined_edges(top_edges, services);
SweptCycle { faces, top_cycle }
}
}
/// The result of sweeping a [`Cycle`]
///
/// See [`SweepCycle`].
pub struct SweptCycle {
/// The faces created by sweeping each half-edge of the cycle
///
/// See [`SweepCycle::sweep_cycle`] for more information.
pub faces: Vec<Face>,
/// 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)
/// and reversed version of the original cycle.
pub top_cycle: Cycle,
}