use fj_math::{Line, Plane, Point, Scalar};
use crate::{
objects::{Curve, GlobalCurve, Surface},
path::{GlobalPath, SurfacePath},
stores::{Handle, Stores},
};
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct SurfaceSurfaceIntersection {
pub intersection_curves: [Handle<Curve>; 2],
}
impl SurfaceSurfaceIntersection {
pub fn compute(
surfaces: [Handle<Surface>; 2],
stores: &Stores,
) -> Option<Self> {
let surfaces_and_planes = surfaces.map(|surface| {
let plane = plane_from_surface(&surface);
(surface, plane)
});
let [a, b] = surfaces_and_planes.clone().map(|(_, plane)| plane);
let (a_distance, a_normal) = a.constant_normal_form();
let (b_distance, b_normal) = b.constant_normal_form();
let direction = a_normal.cross(&b_normal);
let denom = direction.dot(&direction);
if denom == Scalar::ZERO {
return None;
}
let origin = (b_normal * a_distance - a_normal * b_distance)
.cross(&direction)
/ denom;
let origin = Point { coords: origin };
let line = Line::from_origin_and_direction(origin, direction);
let curves = surfaces_and_planes.map(|(surface, plane)| {
let path = SurfacePath::Line(plane.project_line(&line));
let global_form = GlobalCurve::new(stores);
Curve::new(surface, path, global_form, stores)
});
Some(Self {
intersection_curves: curves,
})
}
}
fn plane_from_surface(surface: &Surface) -> Plane {
let (line, path) = {
let line = match surface.u() {
GlobalPath::Line(line) => line,
_ => todo!("Only plane-plane intersection is currently supported."),
};
(line, surface.v())
};
Plane::from_parametric(line.origin(), line.direction(), path)
}
#[cfg(test)]
mod tests {
use fj_math::Transform;
use pretty_assertions::assert_eq;
use crate::{
algorithms::transform::TransformObject,
objects::{Curve, Surface},
partial::HasPartial,
stores::{Handle, Stores},
};
use super::SurfaceSurfaceIntersection;
#[test]
fn plane_plane() {
let stores = Stores::new();
let xy = stores.surfaces.insert(Surface::xy_plane());
let xz = stores.surfaces.insert(Surface::xz_plane());
assert_eq!(
SurfaceSurfaceIntersection::compute(
[
xy.clone(),
xy.clone().transform(
&Transform::translation([0., 0., 1.],),
&stores
)
],
&stores
),
None,
);
let expected_xy = Handle::<Curve>::partial()
.with_surface(Some(xy.clone()))
.as_u_axis()
.build(&stores);
let expected_xz = Handle::<Curve>::partial()
.with_surface(Some(xz.clone()))
.as_u_axis()
.build(&stores);
assert_eq!(
SurfaceSurfaceIntersection::compute([xy, xz], &stores),
Some(SurfaceSurfaceIntersection {
intersection_curves: [expected_xy, expected_xz],
})
);
}
}