diff --git a/crates/fj-kernel/src/algorithms/sweep/face.rs b/crates/fj-kernel/src/algorithms/sweep/face.rs index 638df01ae..1c44e542f 100644 --- a/crates/fj-kernel/src/algorithms/sweep/face.rs +++ b/crates/fj-kernel/src/algorithms/sweep/face.rs @@ -75,3 +75,87 @@ fn create_top_face( face } + +#[cfg(test)] +mod tests { + use fj_interop::mesh::Color; + + use crate::{ + algorithms::{reverse::Reverse, transform::TransformObject}, + objects::{Face, HalfEdge, Sketch, Surface}, + }; + + use super::Sweep; + + const TRIANGLE: [[f64; 2]; 3] = [[0., 0.], [1., 0.], [0., 1.]]; + + const UP: [f64; 3] = [0., 0., 1.]; + const DOWN: [f64; 3] = [0., 0., -1.]; + + #[test] + fn sweep_up() { + let surface = Surface::xy_plane(); + let solid = Sketch::build(surface) + .polygon_from_points(TRIANGLE) + .sweep(UP); + + let bottom = Face::build(surface) + .polygon_from_points(TRIANGLE) + .into_face() + .reverse(); + let top = Face::build(surface.translate(UP)) + .polygon_from_points(TRIANGLE) + .into_face(); + + assert!(solid.find_face(&bottom).is_some()); + assert!(solid.find_face(&top).is_some()); + + let mut side_faces = TRIANGLE.windows(2).map(|window| { + // 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] = [window[0], window[1]]; + + let half_edge = HalfEdge::build(Surface::xy_plane()) + .line_segment_from_points([a, b]); + (half_edge, Color::default()).sweep(UP) + }); + + assert!(side_faces.all(|face| solid.find_face(&face).is_some())); + } + + #[test] + fn sweep_down() { + let surface = Surface::xy_plane(); + let solid = Sketch::build(surface) + .polygon_from_points(TRIANGLE) + .sweep(DOWN); + + let bottom = Face::build(surface.translate(DOWN)) + .polygon_from_points(TRIANGLE) + .into_face() + .reverse(); + let top = Face::build(surface) + .polygon_from_points(TRIANGLE) + .into_face(); + + assert!(solid.find_face(&bottom).is_some()); + assert!(solid.find_face(&top).is_some()); + + let mut side_faces = TRIANGLE.windows(2).map(|window| { + // 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] = [window[0], window[1]]; + + let half_edge = HalfEdge::build(Surface::xy_plane()) + .line_segment_from_points([a, b]) + .reverse(); + (half_edge, Color::default()).sweep(DOWN) + }); + + assert!(side_faces.all(|face| solid.find_face(&face).is_some())); + } +} diff --git a/crates/fj-kernel/src/algorithms/sweep/sketch.rs b/crates/fj-kernel/src/algorithms/sweep/sketch.rs index 6c32798ed..143f2baf3 100644 --- a/crates/fj-kernel/src/algorithms/sweep/sketch.rs +++ b/crates/fj-kernel/src/algorithms/sweep/sketch.rs @@ -19,153 +19,3 @@ impl Sweep for Sketch { Solid::new().with_shells(shells) } } - -#[cfg(test)] -mod tests { - use fj_math::{Point, Vector}; - - use crate::{ - iter::ObjectIters, - objects::{Face, Sketch, Surface}, - }; - - use super::Sweep; - - // This test currently fails, even though the code it tests works correctly. - // Fixing this would require this whole test suite to be refactored. - // - // Since other tests have already been disabled before, diminishing the - // value of this test suite significantly, it's not a big loss to disable - // this rather simple test too, and fix the whole test suite at a later - // date. - #[test] - #[ignore] - fn bottom_positive() -> anyhow::Result<()> { - test_bottom_top( - [0., 0., 1.], - [[0., 0., 0.], [1., 0., 0.], [0., -1., 0.]], - [[0., 0.], [1., 0.], [0., -1.]], - ) - } - - #[test] - fn bottom_negative() -> anyhow::Result<()> { - test_bottom_top( - [0., 0., -1.], - [[0., 0., 0.], [1., 0., 0.], [0., 1., 0.]], - [[0., 0.], [1., 0.], [0., 1.]], - ) - } - - #[test] - fn top_positive() -> anyhow::Result<()> { - test_bottom_top( - [0., 0., 1.], - [[0., 0., 1.], [1., 0., 1.], [0., 1., 1.]], - [[0., 0.], [1., 0.], [0., 1.]], - ) - } - - // This test currently fails, even though the code it tests works correctly. - // Fixing this would require this whole test suite to be refactored. - // - // Since other tests have already been disabled before, diminishing the - // value of this test suite significantly, it's not a big loss to disable - // this rather simple test too, and fix the whole test suite at a later - // date. - #[test] - #[ignore] - fn top_negative() -> anyhow::Result<()> { - test_bottom_top( - [0., 0., -1.], - [[0., 0., -1.], [1., 0., -1.], [0., -1., -1.]], - [[0., 0.], [1., 0.], [0., -1.]], - ) - } - - // This test currently fails, even though the code it tests works correctly. - // At the time this test was disabled, fixing it would have been - // impractical. This has changed since then, thanks to some simplifications. - #[test] - #[ignore] - fn side_positive() -> anyhow::Result<()> { - test_side( - [0., 0., 1.], - [ - [[0., 0., 0.], [1., 0., 0.], [0., 0., 1.]], - [[1., 0., 0.], [0., 1., 0.], [1., 0., 1.]], - [[0., 1., 0.], [0., 0., 0.], [0., 1., 1.]], - ], - ) - } - - // This test currently fails, even though the code it tests works correctly. - // At the time this test was disabled, fixing it would have been - // impractical. This has changed since then, thanks to some simplifications. - #[test] - #[ignore] - fn side_negative() -> anyhow::Result<()> { - test_side( - [0., 0., -1.], - [ - [[0., 0., 0.], [0., 1., 0.], [0., 0., -1.]], - [[0., 1., 0.], [1., 0., 0.], [0., 1., -1.]], - [[1., 0., 0.], [0., 0., 0.], [1., 0., -1.]], - ], - ) - } - - fn test_side( - direction: impl Into>, - expected_surfaces: [[impl Into>; 3]; 3], - ) -> anyhow::Result<()> { - test( - direction, - expected_surfaces, - [[0., 0.], [1., 0.], [1., 1.], [0., 1.]], - ) - } - - fn test_bottom_top( - direction: impl Into>, - expected_surface: [impl Into>; 3], - expected_vertices: [impl Into>; 3], - ) -> anyhow::Result<()> { - test(direction, [expected_surface], expected_vertices) - } - - fn test( - direction: impl Into>, - expected_surfaces: impl IntoIterator>; 3]>, - expected_vertices: impl IntoIterator>>, - ) -> anyhow::Result<()> { - let surface = Surface::xy_plane(); - let face = Face::build(surface).polygon_from_points([ - [0., 0.], - [1., 0.], - [0., 1.], - ]); - let sketch = Sketch::new().with_faces([face]); - - let solid = sketch.sweep(direction); - - let expected_vertices: Vec<_> = expected_vertices - .into_iter() - .map(|vertex| vertex.into()) - .collect(); - - let faces = expected_surfaces.into_iter().map(|surface| { - let surface = Surface::plane_from_points(surface); - - Face::build(surface) - .polygon_from_points(expected_vertices.clone()) - .into_face() - }); - - for face in faces { - assert!(solid.face_iter().any(|f| f == &face)); - } - - Ok(()) - } -}