use geometry_tag::SegmentTag;
use geometry_trait::{
Geometry, IndexedAccess, Point as PointTrait, PointMut, Segment as SegmentTrait,
};
#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Segment<P: PointTrait> {
endpoints: [P; 2],
}
impl<P: PointTrait> Segment<P> {
#[must_use]
pub const fn new(start: P, end: P) -> Self {
Self {
endpoints: [start, end],
}
}
#[must_use]
pub const fn start(&self) -> &P {
&self.endpoints[0]
}
#[must_use]
pub const fn end(&self) -> &P {
&self.endpoints[1]
}
}
impl<P: PointTrait> Geometry for Segment<P> {
type Kind = SegmentTag;
type Point = P;
}
impl<P: PointMut> IndexedAccess for Segment<P> {
#[inline]
fn get_indexed<const I: usize, const D: usize>(&self) -> P::Scalar {
self.endpoints[I].get::<D>()
}
#[inline]
fn set_indexed<const I: usize, const D: usize>(&mut self, value: P::Scalar) {
self.endpoints[I].set::<D>(value);
}
}
impl<P: PointMut> SegmentTrait for Segment<P> {}
#[cfg(test)]
mod tests {
use super::Segment;
use crate::point::Point2D;
use geometry_cs::Cartesian;
use geometry_tag::SegmentTag;
use geometry_trait::{Geometry, IndexedAccess, check_segment};
#[test]
fn segment_round_trip_all_four_slots() {
let mut s = Segment::new(
Point2D::<f64, Cartesian>::default(),
Point2D::<f64, Cartesian>::default(),
);
s.set_indexed::<0, 0>(1.0);
s.set_indexed::<0, 1>(2.0);
s.set_indexed::<1, 0>(3.0);
s.set_indexed::<1, 1>(4.0);
assert_eq!(s.get_indexed::<0, 0>().to_bits(), 1.0_f64.to_bits());
assert_eq!(s.get_indexed::<0, 1>().to_bits(), 2.0_f64.to_bits());
assert_eq!(s.get_indexed::<1, 0>().to_bits(), 3.0_f64.to_bits());
assert_eq!(s.get_indexed::<1, 1>().to_bits(), 4.0_f64.to_bits());
}
#[test]
fn segment_start_and_end_accessors() {
use geometry_trait::Point as PointTrait;
let a = Point2D::<f64, Cartesian>::new(1.0, 2.0);
let b = Point2D::<f64, Cartesian>::new(3.0, 4.0);
let s = Segment::new(a, b);
assert_eq!(s.start().get::<0>().to_bits(), 1.0_f64.to_bits());
assert_eq!(s.start().get::<1>().to_bits(), 2.0_f64.to_bits());
assert_eq!(s.end().get::<0>().to_bits(), 3.0_f64.to_bits());
assert_eq!(s.end().get::<1>().to_bits(), 4.0_f64.to_bits());
}
#[test]
fn segment_kind_is_segment_tag() {
fn k<T: Geometry<Kind = SegmentTag>>() {}
k::<Segment<Point2D<f64, Cartesian>>>();
}
#[test]
fn segment_satisfies_concept() {
check_segment::<Segment<Point2D<f64, Cartesian>>>();
}
}