Skip to content

Commit

Permalink
Merge pull request #1157 from hannobraun/plane
Browse files Browse the repository at this point in the history
Add `Plane`
  • Loading branch information
hannobraun authored Sep 29, 2022
2 parents e6bb954 + 669b2be commit 044a7ed
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 89 deletions.
108 changes: 19 additions & 89 deletions crates/fj-kernel/src/algorithms/intersect/surface_surface.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use fj_math::{Line, Point, Scalar, Vector};
use fj_math::{Line, Plane, Point, Scalar};

use crate::{
objects::{Curve, GlobalCurve, Surface},
Expand All @@ -22,15 +22,16 @@ impl SurfaceSurfaceIntersection {
// Adaptations were made to get the intersection curves in local
// coordinates for each surface.

let planes_parametric = surfaces.map(|surface| {
let plane = PlaneParametric::extract_from_surface(surface);
let surfaces_and_planes = surfaces.map(|surface| {
let plane = plane_from_surface(surface);
(*surface, plane)
});
let [a, b] = planes_parametric.map(|(_, plane)| {
PlaneConstantNormal::from_parametric_plane(&plane)
});
let [a, b] = surfaces_and_planes.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 direction = a_normal.cross(&b_normal);

let denom = direction.dot(&direction);
if denom == Scalar::ZERO {
Expand All @@ -44,15 +45,15 @@ impl SurfaceSurfaceIntersection {
return None;
}

let origin = (b.normal * a.distance - a.normal * b.distance)
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 = planes_parametric.map(|(surface, plane)| {
let path = project_line_into_plane(&line, &plane);
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)
Expand All @@ -64,88 +65,17 @@ impl SurfaceSurfaceIntersection {
}
}

/// A plane in parametric form
#[derive(Clone, Copy)]
struct PlaneParametric {
pub origin: Point<3>,
pub u: Vector<3>,
pub v: Vector<3>,
}

impl PlaneParametric {
pub fn extract_from_surface(surface: &Surface) -> Self {
let (line, path) = {
let line = match surface.u() {
GlobalPath::Line(line) => line,
_ => todo!(
"Only plane-plane intersection is currently supported."
),
};

(line, surface.v())
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."),
};

Self {
origin: line.origin(),
u: line.direction(),
v: path,
}
}
}

/// A plane in constant-normal form
struct PlaneConstantNormal {
pub distance: Scalar,
pub normal: Vector<3>,
}

impl PlaneConstantNormal {
/// Extract a plane in constant-normal form from a `Surface`
///
/// Panics, if the given `Surface` is not a plane.
pub fn from_parametric_plane(plane: &PlaneParametric) -> Self {
// Convert plane from parametric form to three-point form.
let a = plane.origin;
let b = plane.origin + plane.u;
let c = plane.origin + plane.v;

// Convert plane from three-point form to constant-normal form. See
// Real-Time Collision Detection by Christer Ericson, section 3.6, Planes
// and Halfspaces.
let normal = (b - a).cross(&(c - a)).normalize();
let distance = normal.dot(&a.coords);

PlaneConstantNormal { distance, normal }
}
}
(line, surface.v())
};

fn project_line_into_plane(
line: &Line<3>,
plane: &PlaneParametric,
) -> SurfacePath {
let line_origin_relative_to_plane = line.origin() - plane.origin;
let line_origin_in_plane = Vector::from([
plane
.u
.scalar_projection_onto(&line_origin_relative_to_plane),
plane
.v
.scalar_projection_onto(&line_origin_relative_to_plane),
]);

let line_direction_in_plane = Vector::from([
plane.u.scalar_projection_onto(&line.direction()),
plane.v.scalar_projection_onto(&line.direction()),
]);

let line = Line::from_origin_and_direction(
Point {
coords: line_origin_in_plane,
},
line_direction_in_plane,
);

SurfacePath::Line(line)
Plane::from_parametric(line.origin(), line.direction(), path)
}

#[cfg(test)]
Expand Down
2 changes: 2 additions & 0 deletions crates/fj-math/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ mod aabb;
mod circle;
mod coordinates;
mod line;
mod plane;
mod point;
mod poly_chain;
mod scalar;
Expand All @@ -52,6 +53,7 @@ pub use self::{
circle::Circle,
coordinates::{Uv, Xyz, T},
line::Line,
plane::Plane,
point::Point,
poly_chain::PolyChain,
scalar::{Scalar, Sign},
Expand Down
80 changes: 80 additions & 0 deletions crates/fj-math/src/plane.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use crate::{Line, Point, Scalar, Vector};

/// A plane
#[derive(Clone, Copy, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
#[repr(C)]
pub struct Plane {
origin: Point<3>,
u: Vector<3>,
v: Vector<3>,
}

impl Plane {
/// Create a `Plane` from a parametric description
pub fn from_parametric(
origin: Point<3>,
u: Vector<3>,
v: Vector<3>,
) -> Self {
Self { origin, u, v }
}

/// Access the origin of the plane
pub fn origin(&self) -> Point<3> {
self.origin
}

/// Access the u-vector of the plane
pub fn u(&self) -> Vector<3> {
self.u
}

/// Access the v-vector of the plane
pub fn v(&self) -> Vector<3> {
self.v
}

/// Convert the plane to three-point form
pub fn three_point_form(&self) -> [Point<3>; 3] {
let a = self.origin();
let b = self.origin() + self.u();
let c = self.origin() + self.v();

[a, b, c]
}

/// Convert the plane to constant-normal form
pub fn constant_normal_form(&self) -> (Scalar, Vector<3>) {
let [a, b, c] = self.three_point_form();

// See Real-Time Collision Detection by Christer Ericson, section 3.6,
// Planes and Halfspaces.
let normal = (b - a).cross(&(c - a)).normalize();
let distance = normal.dot(&a.coords);

(distance, normal)
}

/// Project a line into the plane
pub fn project_line(&self, line: &Line<3>) -> Line<2> {
let line_origin_relative_to_plane = line.origin() - self.origin();
let line_origin_in_plane = Point {
coords: Vector::from([
self.u()
.scalar_projection_onto(&line_origin_relative_to_plane),
self.v()
.scalar_projection_onto(&line_origin_relative_to_plane),
]),
};

let line_direction_in_plane = Vector::from([
self.u().scalar_projection_onto(&line.direction()),
self.v().scalar_projection_onto(&line.direction()),
]);

Line::from_origin_and_direction(
line_origin_in_plane,
line_direction_in_plane,
)
}
}

0 comments on commit 044a7ed

Please sign in to comment.