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
use crate::builder::CycleBuilder;
use super::{Edge, Surface};
/// A cycle of connected edges
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct Cycle {
surface: Surface,
edges: Vec<Edge>,
}
impl Cycle {
/// Build a cycle using [`CycleBuilder`]
pub fn build(surface: Surface) -> CycleBuilder {
CycleBuilder::new(surface)
}
/// Create a new cycle
///
/// # Panics
///
/// Panic, if the end of each edge does not connect to the beginning of the
/// next edge.
pub fn new(
surface: Surface,
edges: impl IntoIterator<Item = Edge>,
) -> Self {
let edges = edges.into_iter().collect::<Vec<_>>();
// Verify, that the curves of all edges are defined in the correct
// surface.
for edge in &edges {
assert_eq!(
&surface,
edge.curve().surface(),
"Edges in cycle not defined in same surface"
);
}
if edges.len() != 1 {
// If the length is one, we might have a cycle made up of just one
// circle. If that isn't the case, we are dealing with line segments
// and can be sure that the following `get_or_panic` calls won't
// panic.
// Verify that all edges connect.
for edges in edges.windows(2) {
// Can't panic, as we passed `2` to `windows`.
//
// Can be cleaned up, once `array_windows` is stable"
// https://doc.rust-lang.org/std/primitive.slice.html#method.array_windows
let [a, b] = [&edges[0], &edges[1]];
let [_, prev] = a.vertices().get_or_panic();
let [next, _] = b.vertices().get_or_panic();
assert_eq!(
prev.global(),
next.global(),
"Edges in cycle do not connect"
);
}
// Verify that the edges form a cycle
if let Some(first) = edges.first() {
if let Some(last) = edges.last() {
let [first, _] = first.vertices().get_or_panic();
let [_, last] = last.vertices().get_or_panic();
assert_eq!(
first.global(),
last.global(),
"Edges do not form a cycle"
);
}
}
}
Self { surface, edges }
}
/// Access the surface that this cycle is in
pub fn surface(&self) -> &Surface {
&self.surface
}
/// Access edges that make up the cycle
pub fn edges(&self) -> impl Iterator<Item = &Edge> + '_ {
self.edges.iter()
}
/// Consume the cycle and return its edges
pub fn into_edges(self) -> impl Iterator<Item = Edge> {
self.edges.into_iter()
}
}