#![allow(dead_code)]
use crate::{line::Line, point::Point};
use robust::{Coord, orient2d};
#[derive(Debug, PartialEq)]
pub enum LineLineConfig {
ParallelDistinct(),
ParallelTheSame(),
OnePoint(Point, f64, f64), }
const ZERO: f64 = 0f64;
pub fn int_line_line(line0: &Line, line1: &Line) -> LineLineConfig {
let q = line1.origin - line0.origin;
let dot_d0_perp_d1 = line0.dir.perp(line1.dir);
let det = orient2d(
Coord { x: 0.0, y: 0.0 },
Coord {
x: line0.dir.x,
y: line0.dir.y,
},
Coord {
x: line1.dir.x,
y: line1.dir.y,
},
);
if det == 0.0 {
let det_q = orient2d(
Coord { x: 0.0, y: 0.0 },
Coord { x: q.x, y: q.y },
Coord {
x: line1.dir.x,
y: line1.dir.y,
},
);
if det_q == 0.0 {
LineLineConfig::ParallelTheSame()
} else {
LineLineConfig::ParallelDistinct()
}
} else {
let dot_qperp_d0 = q.perp(line0.dir);
let dot_qperp_d1 = q.perp(line1.dir);
if dot_d0_perp_d1.abs() < f64::EPSILON * 1e3 {
LineLineConfig::ParallelDistinct()
} else {
let s0 = dot_qperp_d1 / dot_d0_perp_d1;
let s1 = dot_qperp_d0 / dot_d0_perp_d1;
let dir0_mag = line0.dir.norm();
let dir1_mag = line1.dir.norm();
let q_mag = q.norm();
let input_scale = (dir0_mag + dir1_mag + q_mag).max(1.0);
let max_param = input_scale * 1e8;
if s0.abs() > max_param || s1.abs() > max_param {
LineLineConfig::ParallelDistinct()
} else {
let p = line0.origin + line0.dir * s0;
LineLineConfig::OnePoint(p, s0, s1)
}
}
}
}
#[cfg(test)]
mod test_int_line_line {
use super::*;
use crate::line::line;
use crate::point::{almost_equal_as_int, point};
#[test]
fn test_parallel_distinct() {
let sgrt_2_2 = std::f64::consts::SQRT_2 / 2.0;
let l0 = line(point(0.0, 0.0), point(sgrt_2_2, sgrt_2_2));
let l1 = line(point(f64::EPSILON, 0.0), point(sgrt_2_2, sgrt_2_2));
assert_eq!(int_line_line(&l0, &l1), LineLineConfig::ParallelDistinct());
}
#[test]
fn test_parallel_the_same() {
let sgrt_2_2 = std::f64::consts::SQRT_2 / 2.0;
let l0 = line(point(0.0, 0.0), point(sgrt_2_2, sgrt_2_2));
let l1 = line(point(1.0, 1.0), point(sgrt_2_2, sgrt_2_2));
assert_eq!(int_line_line(&l0, &l1), LineLineConfig::ParallelTheSame());
}
#[test]
fn test_one_point() {
let sgrt_2_2 = std::f64::consts::SQRT_2 / 2.0;
let sgrt_2 = std::f64::consts::SQRT_2;
let l0 = line(point(0.0, 0.0), point(sgrt_2_2, sgrt_2_2));
let l1 = line(point(0.0, 2.0), point(sgrt_2_2, -sgrt_2_2));
let res = int_line_line(&l0, &l1);
match res {
LineLineConfig::OnePoint(p, s0, s1) => {
assert_eq!(p, point(1.0, 1.0));
assert!(almost_equal_as_int(s0, sgrt_2, 1));
assert!(almost_equal_as_int(s1, sgrt_2, 1));
}
_ => assert!(false),
}
}
#[test]
fn test_inersection_issue() {
let line0 = Line::new(point(0.0, 0.0), point(1.0, 1.0));
let line1 = Line::new(point(0.0, 2.0), point(1.0, -1.0));
let result = int_line_line(&line0, &line1);
match result {
LineLineConfig::OnePoint(p, s0, s1) => {
assert_eq!(p, point(1.0, 1.0));
assert_eq!(s0, 1.0);
assert_eq!(s1, 1.0);
}
_ => assert!(false),
}
}
#[test]
fn test_nearly_parallel_lines_with_small_epsilon() {
let line0 = line(point(0.0, 0.0), point(1.0, 0.0));
let line1 = line(point(0.0, 1.0), point(1.0, 1e-8)); let result = int_line_line(&line0, &line1);
match result {
LineLineConfig::ParallelDistinct() | LineLineConfig::OnePoint(_, _, _) => {
}
_ => panic!("Unexpected result for nearly parallel lines"),
}
}
#[test]
fn test_intersection_far_away_rejected() {
let line0 = line(point(0.0, 0.0), point(1.0, 1e-10)); let line1 = line(point(1e-10, 1.0), point(1e-10, 1.0 + 1e-10)); let result = int_line_line(&line0, &line1);
match result {
LineLineConfig::ParallelDistinct() => {
}
_ => {
}
}
}
#[test]
fn test_perpendicular_lines() {
let line0 = line(point(0.0, 0.0), point(1.0, 0.0)); let line1 = line(point(0.5, 0.0), point(0.0, 1.0)); let result = int_line_line(&line0, &line1);
match result {
LineLineConfig::OnePoint(p, _, _) => {
assert_eq!(p, point(0.5, 0.0));
}
_ => panic!("Expected intersection for perpendicular lines"),
}
}
#[test]
fn test_zero_magnitude_direction_check() {
let eps = 1e-15;
let line0 = line(point(0.0, 0.0), point(eps, eps));
let line1 = line(point(0.0, 1.0), point(eps, 1.0 - eps));
let result = int_line_line(&line0, &line1);
match result {
LineLineConfig::ParallelDistinct() | LineLineConfig::OnePoint(_, _, _) => {
}
_ => panic!("Unexpected result"),
}
}
}