use std::ops::RangeInclusive;
use fj_math::Point;
use itertools::Itertools;
use crate::{
geometry::curve::Curve,
objects::{Cycle, HalfEdge},
operations::{BuildHalfEdge, Insert, UpdateCycle, UpdateHalfEdge},
services::Services,
storage::Handle,
};
pub trait JoinCycle {
fn add_joined_edges<Es>(&self, edges: Es, services: &mut Services) -> Self
where
Es: IntoIterator<Item = (Handle<HalfEdge>, Curve, [Point<1>; 2])>,
Es::IntoIter: Clone + ExactSizeIterator;
fn join_to(
&self,
other: &Cycle,
range: RangeInclusive<usize>,
other_range: RangeInclusive<usize>,
services: &mut Services,
) -> Self;
}
impl JoinCycle for Cycle {
fn add_joined_edges<Es>(&self, edges: Es, services: &mut Services) -> Self
where
Es: IntoIterator<Item = (Handle<HalfEdge>, Curve, [Point<1>; 2])>,
Es::IntoIter: Clone + ExactSizeIterator,
{
self.add_half_edges(edges.into_iter().circular_tuple_windows().map(
|((prev, _, _), (half_edge, curve, boundary))| {
HalfEdge::unjoined(curve, boundary, services)
.replace_start_vertex(prev.start_vertex().clone())
.replace_global_form(half_edge.global_form().clone())
.insert(services)
},
))
}
fn join_to(
&self,
other: &Cycle,
range: RangeInclusive<usize>,
range_other: RangeInclusive<usize>,
services: &mut Services,
) -> Self {
assert_eq!(
range.end() - range.start(),
range_other.end() - range_other.start()
);
let mut cycle = self.clone();
for (index, index_other) in range.zip(range_other) {
let index = index % self.len();
let index_other = index_other % self.len();
let half_edge = self
.nth_half_edge(index)
.expect("Index must be valid, due to use of `%` above");
let half_edge_other = other
.nth_half_edge(index_other)
.expect("Index must be valid, due to use of `%` above");
let vertex_a = other
.half_edge_after(half_edge_other)
.expect("Expected other cycle to contain edge")
.start_vertex()
.clone();
let vertex_b = half_edge_other.start_vertex().clone();
let next_edge = cycle
.half_edge_after(half_edge)
.expect("Expected this cycle to contain edge");
let this_joined = half_edge
.replace_start_vertex(vertex_a)
.replace_global_form(half_edge_other.global_form().clone())
.insert(services);
let next_joined =
next_edge.replace_start_vertex(vertex_b).insert(services);
cycle = cycle
.replace_half_edge(half_edge, this_joined)
.replace_half_edge(next_edge, next_joined)
}
cycle
}
}