Skip to content

Commit

Permalink
Add JoinCycle
Browse files Browse the repository at this point in the history
  • Loading branch information
hannobraun committed Apr 24, 2023
1 parent c7e3870 commit 1e05569
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 0 deletions.
100 changes: 100 additions & 0 deletions crates/fj-kernel/src/operations/join/cycle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use std::ops::RangeInclusive;

use crate::{
objects::{Cycle, Objects},
operations::{Insert, UpdateCycle, UpdateHalfEdge},
services::Service,
};

/// Join a [`Cycle`] to another
pub trait JoinCycle {
/// Join the cycle to another
///
/// Joins the cycle to the other at the provided ranges. The ranges specify
/// the indices of the half-edges that are joined together.
///
/// A modulo operation is applied to all indices before use, so in a cycle
/// of 3 half-edges, indices `0` and `3` refer to the same half-edge. This
/// allows for specifying a range that crosses the "seam" of the cycle.
///
/// # Panics
///
/// Panics, if the ranges have different lengths.
///
/// # Implementation Note
///
/// The use of the `RangeInclusive` type might be a bit limiting, as other
/// range types might be more convenient in a given use case. This
/// implementation was chosen for now, as it wasn't clear whether the
/// additional complexity of using `RangeBounds` would be worth it.
///
/// A solution based on `SliceIndex` could theoretically be used, but that
/// trait is partially unstable. In addition, it's not clear how it could be
/// used generically, as it could yield a range (which can be iterated over)
/// or a single item (which can not). This is not a hard problem in
/// principle (a single item could just be an iterator of length 1), but I
/// don't see it how to address this in Rust in a reasonable way.
///
/// Maybe a custom trait that is implemented for `usize` and all range types
/// would be the best solution.
fn join_to(
&self,
other: &Cycle,
range: RangeInclusive<usize>,
other_range: RangeInclusive<usize>,
objects: &mut Service<Objects>,
) -> Self;
}

impl JoinCycle for Cycle {
fn join_to(
&self,
other: &Cycle,
range: RangeInclusive<usize>,
range_other: RangeInclusive<usize>,
objects: &mut Service<Objects>,
) -> 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(objects);
let next_joined =
next_edge.replace_start_vertex(vertex_b).insert(objects);

cycle = cycle
.replace_half_edge(half_edge, this_joined)
.replace_half_edge(next_edge, next_joined)
}

cycle
}
}
3 changes: 3 additions & 0 deletions crates/fj-kernel/src/operations/join/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod cycle;

pub use self::cycle::JoinCycle;
2 changes: 2 additions & 0 deletions crates/fj-kernel/src/operations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
mod build;
mod insert;
mod join;
mod update;

pub use self::{
Expand All @@ -10,5 +11,6 @@ pub use self::{
Polygon, Tetrahedron,
},
insert::Insert,
join::JoinCycle,
update::{UpdateCycle, UpdateFace, UpdateHalfEdge, UpdateShell},
};

0 comments on commit 1e05569

Please sign in to comment.