#![allow(dead_code)]
use crate::prelude::*;
use crate::constants::GEOMETRIC_EPSILON;
const ZERO: f64 = 0f64;
const ONE: f64 = 1f64;
pub fn dist_point_segment(point: &Point, segment: &Segment) -> (f64, Point) {
let direction = segment.b - segment.a;
let sqr_length = direction.dot(direction);
if sqr_length < GEOMETRIC_EPSILON {
return ((point - segment.a).norm(), segment.a);
}
let mut diff = point - segment.b;
let mut t = direction.dot(diff);
if t >= ZERO {
return ((point - segment.b).norm(), segment.b);
}
diff = point - segment.a;
t = direction.dot(diff);
if t <= ZERO {
return ((point - segment.a).norm(), segment.a);
}
let t_normalized = t / sqr_length;
let closest = segment.a + direction * t_normalized;
((point - closest).norm(), closest)
}
#[cfg(test)]
mod test_dist_point_segment {
use crate::{point::point, segment::segment};
#[test]
fn test_point_at_end_01() {
let p = point(0.0, 0.0);
let seg = segment(point(0.0, 0.0), point(1.0, 0.0));
let (dist, closest) = super::dist_point_segment(&p, &seg);
assert_eq!(dist, 0.0);
assert_eq!(closest, point(0.0, 0.0));
}
#[test]
fn test_point_at_end_02() {
let p = point(1.0, 0.0);
let seg = segment(point(0.0, 0.0), point(1.0, 0.0));
let (dist, closest) = super::dist_point_segment(&p, &seg);
assert_eq!(dist, 0.0);
assert_eq!(closest, point(1.0, 0.0));
}
#[test]
fn test_point_inside_segment() {
let p = point(0.5, 0.0);
let seg = segment(point(0.0, 0.0), point(1.0, 0.0));
let (dist, closest) = super::dist_point_segment(&p, &seg);
assert_eq!(dist, 0.0);
assert_eq!(closest, point(0.5, 0.0));
}
#[test]
fn test_point_segment_01() {
let p = point(0.0, 1.0);
let seg = segment(point(0.0, 0.0), point(1.0, 1.0));
let (dist, closest) = super::dist_point_segment(&p, &seg);
assert_eq!(dist, std::f64::consts::SQRT_2 / 2.0);
assert_eq!(closest, point(0.5, 0.5));
}
#[test]
fn test_point_close_to_a_01() {
let p = point(-1.0, 1.0);
let seg = segment(point(0.0, 0.0), point(1.0, 1.0));
let (dist, closest) = super::dist_point_segment(&p, &seg);
assert_eq!(dist, std::f64::consts::SQRT_2);
assert_eq!(closest, point(0.0, 0.0));
}
#[test]
fn test_point_close_to_a_02() {
let p = point(1.0, -1.0);
let seg = segment(point(0.0, 0.0), point(1.0, 1.0));
let (dist, closest) = super::dist_point_segment(&p, &seg);
assert_eq!(dist, std::f64::consts::SQRT_2);
assert_eq!(closest, point(0.0, 0.0));
}
#[test]
fn test_point_close_to_a_03() {
let p = point(-1.0, -1.0);
let seg = segment(point(0.0, 0.0), point(1.0, 1.0));
let (dist, closest) = super::dist_point_segment(&p, &seg);
assert_eq!(dist, std::f64::consts::SQRT_2);
assert_eq!(closest, point(0.0, 0.0));
}
#[test]
fn test_point_close_to_b_01() {
let p = point(0.0, 2.0);
let seg = segment(point(0.0, 0.0), point(1.0, 1.0));
let (dist, closest) = super::dist_point_segment(&p, &seg);
assert_eq!(dist, std::f64::consts::SQRT_2);
assert_eq!(closest, point(1.0, 1.0));
}
#[test]
fn test_point_close_to_b_02() {
let p = point(2.0, 0.0);
let seg = segment(point(0.0, 0.0), point(1.0, 1.0));
let (dist, closest) = super::dist_point_segment(&p, &seg);
assert_eq!(dist, std::f64::consts::SQRT_2);
assert_eq!(closest, point(1.0, 1.0));
}
#[test]
fn test_point_close_to_b_03() {
let p = point(2.0, 2.0);
let seg = segment(point(0.0, 0.0), point(1.0, 1.0));
let (dist, closest) = super::dist_point_segment(&p, &seg);
assert_eq!(dist, std::f64::consts::SQRT_2);
assert_eq!(closest, point(1.0, 1.0));
}
#[test]
fn test_degenerate_segment_zero_length() {
let p = point(1.0, 1.0);
let seg = segment(point(0.0, 0.0), point(0.0, 0.0));
let (dist, closest) = super::dist_point_segment(&p, &seg);
assert_eq!(dist, std::f64::consts::SQRT_2);
assert_eq!(closest, point(0.0, 0.0));
}
}