From 00408c952b2589802d8fe5abd8088f6660f1a5b0 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Mon, 11 Jul 2022 17:18:25 +0200 Subject: [PATCH 1/2] Add dependency on `parry2d-f64` to `fj-kernel` --- Cargo.lock | 1 + crates/fj-kernel/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 041347a87..33c342b93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -893,6 +893,7 @@ dependencies = [ "fj-math", "map-macro", "parking_lot 0.12.1", + "parry2d-f64", "pretty_assertions", "robust", "slotmap", diff --git a/crates/fj-kernel/Cargo.toml b/crates/fj-kernel/Cargo.toml index 056d355b0..42a856cc6 100644 --- a/crates/fj-kernel/Cargo.toml +++ b/crates/fj-kernel/Cargo.toml @@ -16,6 +16,7 @@ categories = ["encoding", "mathematics", "rendering"] anymap = "1.0.0-beta.2" map-macro = "0.2.2" parking_lot = "0.12.0" +parry2d-f64 = "0.9.0" robust = "0.2.3" slotmap = "1.0.6" spade = "2.0.0" From 6f6fb6b095eb30ff0aaa711b0c2fee8836c7fe30 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Mon, 9 May 2022 16:47:52 +0200 Subject: [PATCH 2/2] Add `intersection::curve_face` --- .../src/algorithms/intersection/curve_face.rs | 126 ++++++++++++++++++ .../src/algorithms/intersection/mod.rs | 2 + 2 files changed, 128 insertions(+) create mode 100644 crates/fj-kernel/src/algorithms/intersection/curve_face.rs diff --git a/crates/fj-kernel/src/algorithms/intersection/curve_face.rs b/crates/fj-kernel/src/algorithms/intersection/curve_face.rs new file mode 100644 index 000000000..267d4bd67 --- /dev/null +++ b/crates/fj-kernel/src/algorithms/intersection/curve_face.rs @@ -0,0 +1,126 @@ +use fj_math::{Scalar, Segment}; +use parry2d_f64::query::{Ray, RayCast}; + +use crate::objects::{Curve, Face}; + +/// Determine the intersection between a [`Curve`] and a [`Face`] +/// +/// Returns a list of intersections in curve coordinates. +pub fn curve_face(curve: &Curve<2>, face: &Face) -> Vec<[Scalar; 2]> { + let line = match curve { + Curve::Line(line) => line, + _ => todo!("Curve-face intersection only supports lines"), + }; + + let face_as_polygon = face + .exteriors() + .chain(face.interiors()) + .flat_map(|cycle| { + let edges: Vec<_> = cycle.edges().collect(); + edges + }) + .map(|edge| { + let line = match edge.curve.local() { + Curve::Line(line) => line, + _ => todo!("Curve-face intersection only supports polygons"), + }; + + let vertices = match edge.vertices() { + Some(vertices) => vertices, + None => todo!( + "Curve-face intersection does not support faces with \ + continuous edges" + ), + }; + + (line, vertices) + }); + + let mut intersections = Vec::new(); + + for (edge_line, vertices) in face_as_polygon { + let vertices = vertices + .map(|vertex| edge_line.point_from_line_coords(vertex.position())); + let segment = Segment::from_points(vertices); + + let ray = Ray { + origin: line.origin.to_na(), + dir: line.direction.to_na(), + }; + let ray_inv = Ray { + origin: line.origin.to_na(), + dir: -line.direction.to_na(), + }; + + let result = + segment + .to_parry() + .cast_local_ray(&ray, f64::INFINITY, false); + let result_inv = + segment + .to_parry() + .cast_local_ray(&ray_inv, f64::INFINITY, false); + + if let Some(result) = result { + intersections.push(Scalar::from(result)); + } + if let Some(result_inv) = result_inv { + intersections.push(-Scalar::from(result_inv)); + } + } + + assert!(intersections.len() % 2 == 0); + + intersections.sort(); + + // Can be cleaned up, once `array_chunks` is stable: + // https://doc.rust-lang.org/std/primitive.slice.html#method.array_chunks + intersections + .chunks(2) + .map(|chunk| { + // Can't panic, as we passed `2` to `windows`. + [chunk[0], chunk[1]] + }) + .collect() +} + +#[cfg(test)] +mod tests { + use fj_math::{Line, Point, Scalar, Vector}; + + use crate::objects::{Curve, Face, Surface}; + + #[test] + fn curve_face() { + let curve = Curve::Line(Line { + origin: Point::from([-3., 0.]), + direction: Vector::from([1., 0.]), + }); + + #[rustfmt::skip] + let exterior = [ + [-2., -2.], + [ 2., -2.], + [ 2., 2.], + [-2., 2.], + ]; + #[rustfmt::skip] + let interior = [ + [-1., -1.], + [ 1., -1.], + [ 1., 1.], + [-1., 1.], + ]; + + let face = Face::builder(Surface::xy_plane()) + .with_exterior_polygon(exterior) + .with_interior_polygon(interior) + .build(); + + let expected: Vec<_> = [[1., 2.], [4., 5.]] + .into_iter() + .map(|interval: [f64; 2]| interval.map(Scalar::from)) + .collect(); + assert_eq!(super::curve_face(&curve, &face), expected); + } +} diff --git a/crates/fj-kernel/src/algorithms/intersection/mod.rs b/crates/fj-kernel/src/algorithms/intersection/mod.rs index a5d1542da..0a5b0b0ac 100644 --- a/crates/fj-kernel/src/algorithms/intersection/mod.rs +++ b/crates/fj-kernel/src/algorithms/intersection/mod.rs @@ -1,9 +1,11 @@ //! Intersection algorithms +mod curve_face; mod line_segment; mod surface_surface; pub use self::{ + curve_face::curve_face, line_segment::{line_segment, LineSegmentIntersection}, surface_surface::surface_surface, };