use std::fmt::Display;
use std::sync::atomic::AtomicUsize;
use crate::point::Point;
static ID_COUNT: AtomicUsize = AtomicUsize::new(0);
#[derive(Debug, Copy, Clone)]
pub struct Segment {
pub a: Point,
pub b: Point,
pub id: usize,
}
impl Display for Segment {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{}, {}]", self.a, self.b)
}
}
impl PartialEq for Segment {
fn eq(&self, other: &Self) -> bool {
self.a == other.a && self.b == other.b
}
}
impl Segment {
#[inline]
pub fn new(a: Point, b: Point) -> Self {
let id = ID_COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
Segment { a, b, id }
}
#[inline]
pub fn id(&mut self, id: usize) {
self.id = id;
}
}
#[inline]
pub fn segment(p0: Point, p1: Point) -> Segment {
Segment::new(p0, p1)
}
impl Segment {
#[must_use]
pub fn get_centered_form(&self) -> (Point, Point, f64) {
let center = (self.a + self.b) * 0.5;
let dir = self.b - self.a;
let (dirn, norm) = dir.normalize(false);
let extent = norm * 0.5;
(center, dirn, extent)
}
}
#[cfg(test)]
mod test_segment {
use crate::point::point;
use super::*;
#[test]
fn test_new() {
let s0 = Segment::new(point(1.0, 2.0), point(3.0, 4.0));
let s1 = segment(point(1.0, 2.0), point(3.0, 4.0));
assert_eq!(s0, s1);
}
#[test]
fn test_display() {
let s0 = Segment::new(point(1.0, 2.0), point(3.0, 4.0));
assert_eq!(
"[[1.00000000000000000000, 2.00000000000000000000], [3.00000000000000000000, 4.00000000000000000000]]",
format!("{}", s0)
);
}
#[test]
fn test_get_centered_form() {
let s0 = Segment::new(point(1.0, 1.0), point(3.0, 3.0));
let (center, dir, extent) = s0.get_centered_form();
assert_eq!(center, point(2.0, 2.0));
assert_eq!(dir, point(0.7071067811865475, 0.7071067811865475));
assert_eq!(extent, 1.4142135623730951);
}
#[test]
fn test_get_centered_form_edge_cases() {
let s_zero = Segment::new(point(5.0, 3.0), point(5.0, 3.0));
let (center, dir, extent) = s_zero.get_centered_form();
assert_eq!(center, point(5.0, 3.0));
assert_eq!(extent, 0.0);
assert_eq!(dir.x, 0.0);
assert_eq!(dir.y, 0.0);
let s_horiz = Segment::new(point(0.0, 2.0), point(6.0, 2.0));
let (center, dir, extent) = s_horiz.get_centered_form();
assert_eq!(center, point(3.0, 2.0));
assert_eq!(dir, point(1.0, 0.0));
assert_eq!(extent, 3.0);
let s_vert = Segment::new(point(1.0, -2.0), point(1.0, 4.0));
let (center, dir, extent) = s_vert.get_centered_form();
assert_eq!(center, point(1.0, 1.0));
assert_eq!(dir, point(0.0, 1.0));
assert_eq!(extent, 3.0);
}
}