Skip to content

Commit

Permalink
Merge pull request #2093 from hannobraun/split
Browse files Browse the repository at this point in the history
Add edge splitting operation
  • Loading branch information
hannobraun authored Nov 14, 2023
2 parents 9bce803 + 8e9b68a commit bac487b
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 4 deletions.
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ members = [
"models/all",
"models/cuboid",
"models/spacer",
"models/split",
"models/star",

"tools/autolib",
Expand Down
61 changes: 61 additions & 0 deletions crates/fj-core/src/operations/split/edge.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use fj_math::Point;

use crate::{
objects::{HalfEdge, Shell},
operations::{
insert::Insert, replace::ReplaceHalfEdge, split::SplitHalfEdge,
update::UpdateHalfEdge,
},
queries::SiblingOfHalfEdge,
services::Services,
storage::Handle,
};

/// Split a pair of [`HalfEdge`]s into two
pub trait SplitEdge {
/// Split the provided [`HalfEdge`], as well as its sibling, into two
///
/// # Panics
///
/// Panics, if the provided half-edge is not a part of this shell.
#[must_use]
fn split_edge(
&self,
half_edge: &Handle<HalfEdge>,
point: impl Into<Point<1>>,
services: &mut Services,
) -> Self;
}

impl SplitEdge for Shell {
fn split_edge(
&self,
half_edge: &Handle<HalfEdge>,
point: impl Into<Point<1>>,
services: &mut Services,
) -> Self {
let point = point.into();

let sibling = self
.get_sibling_of(half_edge)
.expect("Expected half-edge and its sibling to be part of shell");

let [half_edge_a, half_edge_b] = half_edge
.split_half_edge(point, services)
.map(|half_edge| half_edge.insert(services));

let [sibling_a, sibling_b] = sibling.split_half_edge(point, services);
let sibling_b = sibling_b
.update_start_vertex(|_| half_edge_b.start_vertex().clone());

self.replace_half_edge(half_edge, [half_edge_a, half_edge_b], services)
.into_inner()
.replace_half_edge(
&sibling,
[sibling_a, sibling_b]
.map(|half_edge| half_edge.insert(services)),
services,
)
.into_inner()
}
}
5 changes: 5 additions & 0 deletions crates/fj-core/src/operations/split/half_edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ use crate::{
};

/// Split a [`HalfEdge`] into two
///
/// This is a low-level operation that, by itself, leaves the containing shell
/// in an invalid state. You probably want to use [`SplitEdge`] instead.
///
/// [`SplitEdge`]: super::SplitEdge
pub trait SplitHalfEdge {
/// Split the half-edge into two
///
Expand Down
9 changes: 6 additions & 3 deletions crates/fj-core/src/operations/split/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
//! # Operations to split objects
//!
//! See [`SplitHalfEdge`], which is currently the only trait in this module, for
//! more information.
//! Splitting means removing an object, replacing it with to new ones that fill
//! the same space. This often makes sense, when you want to modify only part of
//! an object. In such a case, you can split off the part you want to modify,
//! leaving the rest unchanged.

mod edge;
mod half_edge;

pub use self::half_edge::SplitHalfEdge;
pub use self::{edge::SplitEdge, half_edge::SplitHalfEdge};
3 changes: 3 additions & 0 deletions models/all/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,8 @@ path = "../cuboid"
[dependencies.spacer]
path = "../spacer"

[dependencies.split]
path = "../split"

[dependencies.star]
path = "../star"
9 changes: 8 additions & 1 deletion models/all/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ pub fn model(services: &mut Services) -> Handle<Solid> {
let star = star::model(5, 2., 1., 1., services)
.translate(offset * 3., services)
.rotate(axis * angle_rad * 3., services);
let split = split::model(1., 0.5, services)
.translate(offset * 4., services)
.rotate(axis * angle_rad * 4., services);

cuboid.merge(&spacer).merge(&star).insert(services)
cuboid
.merge(&spacer)
.merge(&star)
.merge(&split)
.insert(services)
}
7 changes: 7 additions & 0 deletions models/split/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "split"
version = "0.1.0"
edition = "2021"

[dependencies.fj]
path = "../../crates/fj"
58 changes: 58 additions & 0 deletions models/split/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use fj::{
core::{
algorithms::sweep::Sweep,
objects::{Region, Sketch, Solid},
operations::{
build::{BuildRegion, BuildSketch},
insert::Insert,
split::SplitEdge,
update::{UpdateSketch, UpdateSolid},
},
services::Services,
storage::Handle,
},
math::Vector,
};

pub fn model(
size: f64,
split_pos: f64,
services: &mut Services,
) -> Handle<Solid> {
let sketch = Sketch::empty()
.add_region(
Region::polygon(
[
[-size / 2., -size / 2.],
[size / 2., -size / 2.],
[size / 2., size / 2.],
[-size / 2., size / 2.],
],
services,
)
.insert(services),
)
.insert(services);

let surface = services.objects.surfaces.xy_plane();
let path = Vector::from([0., 0., size]);
let solid = (sketch, surface).sweep(path, services);

solid
.update_shell(solid.shells().only(), |shell| {
shell
.split_edge(
shell
.faces()
.first()
.region()
.exterior()
.half_edges()
.first(),
[split_pos],
services,
)
.insert(services)
})
.insert(services)
}
8 changes: 8 additions & 0 deletions models/split/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use fj::{core::services::Services, handle_model};

fn main() -> fj::Result {
let mut services = Services::new();
let model = split::model(1.0, 0.5, &mut services);
handle_model(model, services)?;
Ok(())
}

0 comments on commit bac487b

Please sign in to comment.