Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand API of Plane #1160

Merged
merged 6 commits into from
Sep 30, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 25 additions & 29 deletions crates/fj-kernel/src/algorithms/intersect/ray_face.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Intersection between a ray and a face, in 3D
use fj_math::{Point, Scalar};
use fj_math::{Plane, Point, Scalar};

use crate::{
algorithms::intersect::face_point::FacePointIntersection,
@@ -16,25 +16,21 @@ impl Intersect for (&HorizontalRayToTheRight<3>, &Face) {
fn intersect(self) -> Option<Self::Intersection> {
let (ray, face) = self;

let (plane_origin, plane_direction_1, plane_direction_2) =
match face.surface().u() {
GlobalPath::Circle(_) => todo!(
"Casting a ray against a swept circle is not supported yet"
),
GlobalPath::Line(line) => {
(line.origin(), line.direction(), face.surface().v())
}
};

let plane_and_ray_are_parallel = {
let plane_normal = plane_direction_1.cross(&plane_direction_2);
plane_normal.dot(&ray.direction()) == Scalar::ZERO
let plane = match face.surface().u() {
GlobalPath::Circle(_) => todo!(
"Casting a ray against a swept circle is not supported yet"
),
GlobalPath::Line(line) => Plane::from_parametric(
line.origin(),
line.direction(),
face.surface().v(),
),
};

if plane_and_ray_are_parallel {
let a = plane_origin;
let b = plane_origin + plane_direction_1;
let c = plane_origin + plane_direction_2;
if plane.is_parallel_to_vector(&ray.direction()) {
let a = plane.origin();
let b = plane.origin() + plane.u();
let c = plane.origin() + plane.v();
let d = ray.origin;

let [a, b, c, d] = [a, b, c, d]
@@ -63,8 +59,8 @@ impl Intersect for (&HorizontalRayToTheRight<3>, &Face) {
// We already handled the case of the ray and plane being parallel
// above. The following assertion should thus never be triggered.
assert_ne!(
plane_direction_1.y * plane_direction_2.z,
plane_direction_1.z * plane_direction_2.y,
plane.u().y * plane.v().z,
plane.u().z * plane.v().y,
"Plane and ray are parallel; should have been ruled out previously"
);

@@ -75,15 +71,15 @@ impl Intersect for (&HorizontalRayToTheRight<3>, &Face) {
let orx = ray.origin.x;
let ory = ray.origin.y;
let orz = ray.origin.z;
let opx = plane_origin.x;
let opy = plane_origin.y;
let opz = plane_origin.z;
let d1x = plane_direction_1.x;
let d1y = plane_direction_1.y;
let d1z = plane_direction_1.z;
let d2x = plane_direction_2.x;
let d2y = plane_direction_2.y;
let d2z = plane_direction_2.z;
let opx = plane.origin().x;
let opy = plane.origin().y;
let opz = plane.origin().z;
let d1x = plane.u().x;
let d1y = plane.u().y;
let d1z = plane.u().z;
let d2x = plane.v().x;
let d2y = plane.v().y;
let d2z = plane.v().z;

// Let's figure out where the intersection between the ray and the
// plane is. By equating the parametric equations of the ray and the
31 changes: 21 additions & 10 deletions crates/fj-math/src/plane.rs
Original file line number Diff line number Diff line change
@@ -34,6 +34,11 @@ impl Plane {
self.v
}

/// Compute the normal of the plane
pub fn normal(&self) -> Vector<3> {
self.u().cross(&self.v()).normalize()
}

/// Convert the plane to three-point form
pub fn three_point_form(&self) -> [Point<3>; 3] {
let a = self.origin();
@@ -45,16 +50,25 @@ impl Plane {

/// 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);
let normal = self.normal();
let distance = normal.dot(&self.origin().coords);

(distance, normal)
}

/// Determine whether the plane is parallel to the given vector
pub fn is_parallel_to_vector(&self, vector: &Vector<3>) -> bool {
self.normal().dot(vector) == Scalar::ZERO
}

/// Project a vector into the plane
pub fn project_vector(&self, vector: &Vector<3>) -> Vector<2> {
Vector::from([
self.u().scalar_projection_onto(vector),
self.v().scalar_projection_onto(vector),
])
}

/// 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();
@@ -67,10 +81,7 @@ impl Plane {
]),
};

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

Line::from_origin_and_direction(
line_origin_in_plane,