use crate::{Circle3D, Ellipse3D, Hyperbola3D, Line3D, Parabola3D, Point2D, Point3D, Tolerance};
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PlanePlaneIntersection {
Line(Line3D),
Parallel,
Coincident,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PlaneSphereIntersection {
Circle(Circle3D),
TangentPoint(Point3D),
Empty,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum SphereSphereIntersection {
Circle(Circle3D),
TangentPoint(Point3D),
Empty,
Coincident,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PlaneCylinderIntersection {
Circle(Circle3D),
Ellipse(Ellipse3D),
TwoLines(Line3D, Line3D),
TangentLine(Line3D),
Empty,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PlaneConeIntersection {
Circle(Circle3D),
Ellipse(Ellipse3D),
Parabola(Parabola3D),
Hyperbola(Hyperbola3D),
TwoLines(Line3D, Line3D),
TangentLine(Line3D),
ApexPoint(Point3D),
Empty,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LinePlaneIntersection {
Point(f64, Point3D),
Parallel,
Coincident,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LineQuadricIntersection {
TwoPoints((f64, Point3D), (f64, Point3D)),
OnePoint(f64, Point3D),
Tangent(f64, Point3D),
Empty,
Coincident,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum SphereCylinderIntersection {
Circle(Circle3D),
TwoCircles(Circle3D, Circle3D),
Empty,
NotAnalytic,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum SphereConeIntersection {
Circle(Circle3D),
TwoCircles(Circle3D, Circle3D),
TangentCircle(Circle3D),
Empty,
NotAnalytic,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CylinderCylinderIntersection {
TwoLines(Line3D, Line3D),
TangentLine(Line3D),
Empty,
Coincident,
NotAnalytic,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ConeCylinderIntersection {
Circle(Circle3D),
ApexPoint(Point3D),
NotAnalytic,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TorusPlaneIntersection {
TwoCircles(Circle3D, Circle3D),
TangentCircle(Circle3D),
Circle(Circle3D),
Empty,
NotAnalytic,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TorusSphereIntersection {
Circle(Circle3D),
TwoCircles(Circle3D, Circle3D),
TangentCircle(Circle3D),
Empty,
NotAnalytic,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TorusCylinderIntersection {
TwoCircles(Circle3D, Circle3D),
TangentCircle(Circle3D),
Empty,
NotAnalytic,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TorusConeIntersection {
Circle(Circle3D),
TwoCircles(Circle3D, Circle3D),
TangentCircle(Circle3D),
Empty,
NotAnalytic,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TorusTorusIntersection {
Circle(Circle3D),
TwoCircles(Circle3D, Circle3D),
TangentCircle(Circle3D),
Empty,
Coincident,
NotAnalytic,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ConeConeIntersection {
Circle(Circle3D),
ApexPoint(Point3D),
Empty,
Coincident,
NotAnalytic,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LineLine2DIntersection {
Point(f64, Point2D, f64),
Parallel,
Coincident,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LineCircle2DIntersection {
Points((f64, Point2D), (f64, Point2D)),
Tangent(f64, Point2D),
Empty,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CircleCircle2DIntersection {
Points(Point2D, Point2D),
Tangent(Point2D),
Empty,
Coincident,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LineLine3DIntersection {
Point(f64, Point3D, f64),
Parallel(f64),
Coincident,
Skew {
s: f64,
t: f64,
distance: f64,
},
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LineCircle3DIntersection {
Points((f64, Point3D), (f64, Point3D)),
Tangent(f64, Point3D),
Empty,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CircleCircle3DIntersection {
Points(Point3D, Point3D),
Tangent(Point3D),
Empty,
Coincident,
NotAnalytic,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) enum QuadraticSolution {
Two(f64, f64),
One(f64),
Linear(f64),
Degenerate,
Empty,
}
pub(crate) fn solve_quadratic(a: f64, b: f64, c: f64, tol: Tolerance) -> QuadraticSolution {
if a.abs() <= tol.angular {
if b.abs() <= tol.confusion {
return QuadraticSolution::Degenerate;
}
return QuadraticSolution::Linear(-c / b);
}
let disc = b * b - 4.0 * a * c;
let mid = -b / (2.0 * a);
let sep = disc.abs().sqrt() / (2.0 * a.abs());
if sep <= tol.confusion * (1.0 + mid.abs()) {
QuadraticSolution::One(mid)
} else if disc < 0.0 {
QuadraticSolution::Empty
} else {
let (t1, t2) = (mid - sep, mid + sep);
QuadraticSolution::Two(t1, t2)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Tolerance;
#[test]
fn test_solve_quadratic_two_roots_ordered() {
assert_eq!(
solve_quadratic(1.0, -5.0, 6.0, Tolerance::DEFAULT),
QuadraticSolution::Two(2.0, 3.0)
);
}
#[test]
fn test_solve_quadratic_tangent_band() {
assert_eq!(
solve_quadratic(1.0, -4.0, 4.0, Tolerance::DEFAULT),
QuadraticSolution::One(2.0)
);
assert_eq!(
solve_quadratic(1.0, 0.0, 1e-14, Tolerance::DEFAULT),
QuadraticSolution::One(0.0)
);
assert_eq!(
solve_quadratic(1.0, 0.0, 1e-9, Tolerance::DEFAULT),
QuadraticSolution::Empty
);
assert_eq!(
solve_quadratic(1.0, 0.0, 1.0, Tolerance::DEFAULT),
QuadraticSolution::Empty
);
}
#[test]
fn test_solve_quadratic_degenerate_arms() {
assert_eq!(
solve_quadratic(0.0, 2.0, 4.0, Tolerance::DEFAULT),
QuadraticSolution::Linear(-2.0)
);
assert_eq!(
solve_quadratic(0.0, 0.0, 1.0, Tolerance::DEFAULT),
QuadraticSolution::Degenerate
);
}
}