use num::Float;
use ffi;
#[repr(C)]
pub struct Point<T: Float> {
pub x: T,
pub y: T,
}
#[repr(C)]
pub struct LineSegment<T: Float> {
pub from: Point<T>,
pub to: Point<T>,
}
#[derive(PartialEq, Debug)]
pub enum Orientation {
Inside,
On,
Outside,
}
impl<T: Float> Point<T> {
pub fn new(x: T, y: T) -> Self {
Point { x: x, y: y }
}
}
impl Point<f64> {
pub fn orient_to_points(&self, p1: &Point<f64>, p2: &Point<f64>) -> Orientation {
unsafe {
let t = ffi::orient2d(&p1.x, &p2.x, &self.x);
Orientation::from_signed_distance(t)
}
}
pub fn orient_to_circle(&self,
p1: &Point<f64>,
p2: &Point<f64>,
p3: &Point<f64>)
-> Orientation {
unsafe {
let t = ffi::incircle(&p1.x, &p2.x, &p3.x, &self.x);
Orientation::from_signed_distance(t)
}
}
}
impl Orientation {
pub fn from_signed_distance<T: Float>(t: T) -> Orientation {
if t.is_zero() {
Orientation::On
} else if t.is_sign_positive() {
Orientation::Inside
} else {
Orientation::Outside
}
}
}
#[cfg(test)]
mod tests {
use ::arithmetic;
use primitives::Point;
use primitives::Orientation;
#[test]
fn orient_points() {
let _ = arithmetic::Library::init();
let a = Point::new(0.0, 0.0);
let b = Point::new(1.0, 0.0);
let c = Point::new(1.0, 1.0);
let d = Point::new(2.0, 0.0);
assert!(matches!(c.orient_to_points(&a, &b), Orientation::Inside));
assert!(matches!(c.orient_to_points(&b, &a), Orientation::Outside));
assert!(matches!(d.orient_to_points(&a, &b), Orientation::On));
assert!(matches!(a.orient_to_points(&a, &b), Orientation::On));
assert!(matches!(b.orient_to_points(&a, &b), Orientation::On));
assert!(matches!(a.orient_to_points(&a, &a), Orientation::On));
}
#[test]
fn in_circle() {
let _ = arithmetic::Library::init();
let a = Point::new(-1.0, 1.0);
let b = Point::new(1.0, 1.0);
let c = Point::new(0.0, 2.0);
let p1 = Point::new(0.0, 0.0); let p2 = Point::new(0.1, 0.5); let p3 = Point::new(0.1, -0.5);
assert!(matches!(p1.orient_to_circle(&a, &b, &c), Orientation::On));
assert!(matches!(p2.orient_to_circle(&a, &b, &c), Orientation::Inside));
assert!(matches!(p3.orient_to_circle(&a, &b, &c), Orientation::Outside));
}
}