use crate::{Point, Rect};
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
pub struct Segment {
pub a: Point,
pub b: Point,
}
impl Segment {
#[inline]
pub const fn new(a: Point, b: Point) -> Self {
Self { a, b }
}
#[inline]
pub fn rect(self) -> Rect {
let r = unsafe { tg_geom_sys::tg_segment_rect(self.into()) };
r.into()
}
#[inline]
pub fn intersects_segment(self, other: Segment) -> bool {
unsafe { tg_geom_sys::tg_segment_intersects_segment(self.into(), other.into()) }
}
}
impl From<tg_geom_sys::tg_segment> for Segment {
#[inline]
fn from(s: tg_geom_sys::tg_segment) -> Self {
Self {
a: s.a.into(),
b: s.b.into(),
}
}
}
impl From<Segment> for tg_geom_sys::tg_segment {
#[inline]
fn from(s: Segment) -> Self {
Self {
a: s.a.into(),
b: s.b.into(),
}
}
}
impl From<(Point, Point)> for Segment {
#[inline]
fn from((a, b): (Point, Point)) -> Self {
Self { a, b }
}
}
#[cfg(test)]
mod tests {
use super::*;
fn p(x: f64, y: f64) -> Point {
Point::new(x, y)
}
fn s(ax: f64, ay: f64, bx: f64, by: f64) -> Segment {
Segment::new(p(ax, ay), p(bx, by))
}
#[test]
fn test_segment_new() {
let seg = Segment::new(p(1.0, 2.0), p(3.0, 4.0));
assert_eq!(seg.a, p(1.0, 2.0));
assert_eq!(seg.b, p(3.0, 4.0));
}
#[test]
fn test_segment_rect() {
let seg1 = s(1.0, 2.0, 4.0, 6.0);
let rect1 = seg1.rect();
assert_eq!(rect1.min, p(1.0, 2.0));
assert_eq!(rect1.max, p(4.0, 6.0));
let seg2 = s(4.0, 6.0, 1.0, 2.0);
let rect2 = seg2.rect();
assert_eq!(rect2.min, p(1.0, 2.0));
assert_eq!(rect2.max, p(4.0, 6.0));
let seg3 = s(5.0, 5.0, 5.0, 5.0);
let rect3 = seg3.rect();
assert_eq!(rect3.min, rect3.max);
let seg4 = s(0.0, 5.0, 10.0, 5.0);
let rect4 = seg4.rect();
assert_eq!(rect4.min.y, rect4.max.y);
let seg5 = s(5.0, 0.0, 5.0, 10.0);
let rect5 = seg5.rect();
assert_eq!(rect5.min.x, rect5.max.x);
}
#[test]
fn test_segment_intersects_segment_crossing() {
let seg1 = s(0.0, 0.0, 1.0, 1.0);
let seg2 = s(0.0, 1.0, 1.0, 0.0);
assert!(seg1.intersects_segment(seg2));
}
#[test]
fn test_segment_intersects_segment_no_intersection() {
let seg1 = s(0.0, 0.0, 1.0, 1.0);
let seg2 = s(2.0, 2.0, 3.0, 3.0);
assert!(!seg1.intersects_segment(seg2));
}
#[test]
fn test_segment_intersects_segment_parallel() {
let seg1 = s(0.0, 0.0, 1.0, 0.0);
let seg2 = s(0.0, 1.0, 1.0, 1.0);
assert!(!seg1.intersects_segment(seg2));
}
#[test]
fn test_segment_intersects_segment_collinear_overlap() {
let seg1 = s(0.0, 0.0, 2.0, 0.0);
let seg2 = s(1.0, 0.0, 3.0, 0.0);
assert!(seg1.intersects_segment(seg2));
}
#[test]
fn test_segment_intersects_segment_endpoint_touch() {
let seg1 = s(0.0, 0.0, 1.0, 0.0);
let seg2 = s(1.0, 0.0, 2.0, 0.0);
assert!(seg1.intersects_segment(seg2));
}
#[test]
fn test_segment_intersects_segment_t_intersection() {
let seg1 = s(0.0, 0.0, 10.0, 0.0);
let seg2 = s(5.0, 0.0, 5.0, 10.0);
assert!(seg1.intersects_segment(seg2));
}
#[test]
fn test_segment_intersects_segment_self() {
let seg = s(0.0, 0.0, 1.0, 1.0);
assert!(seg.intersects_segment(seg));
}
#[test]
fn test_segment_intersects_segment_vertical() {
let seg1 = s(4.0, 4.0, 4.0, 4.0);
let seg2 = s(4.0, 4.0, 4.0, 4.0);
assert!(seg1.intersects_segment(seg2));
let seg3 = s(5.0, 0.0, 5.0, 10.0);
let seg4 = s(0.0, 5.0, 10.0, 5.0);
assert!(seg3.intersects_segment(seg4));
}
#[test]
fn test_segment_from_points() {
let seg: Segment = (p(1.0, 2.0), p(3.0, 4.0)).into();
assert_eq!(seg.a, p(1.0, 2.0));
assert_eq!(seg.b, p(3.0, 4.0));
}
#[test]
fn test_segment_sys_roundtrip() {
let seg = s(1.0, 2.0, 3.0, 4.0);
let sys_seg: tg_geom_sys::tg_segment = seg.into();
let back: Segment = sys_seg.into();
assert_eq!(seg, back);
}
#[test]
fn test_segment_eq() {
assert_eq!(s(0.0, 0.0, 1.0, 1.0), s(0.0, 0.0, 1.0, 1.0));
assert_ne!(s(0.0, 0.0, 1.0, 1.0), s(0.0, 0.0, 2.0, 2.0));
}
#[test]
fn test_segment_debug() {
let seg = s(1.0, 2.0, 3.0, 4.0);
let debug_str = format!("{seg:?}");
assert!(debug_str.contains("Segment"));
}
#[test]
fn test_segment_negative_coords() {
let seg = s(-5.0, -3.0, -1.0, -7.0);
let rect = seg.rect();
assert_eq!(rect.min.x, -5.0);
assert_eq!(rect.min.y, -7.0);
assert_eq!(rect.max.x, -1.0);
assert_eq!(rect.max.y, -3.0);
}
}