#[allow(dead_code)]
mod geometry {
use std::ops::{Add, Div, Mul, Sub};
use num::{Float, Num};
/// Returns a list of points on the convex hull in counter-clockwise order.
/// Note: the last point in the returned list is the same as the first one.
pub fn construct_convex_hull<T>(mut points: Vec<Vector2D<T>>) -> Vec<Vector2D<T>>
where
T: Num + Copy + PartialOrd + Eq,
{
let n = points.len();
if n <= 3 {
points.push(points[0]);
return points;
}
let mut k = 0;
let mut convex_hull = vec![];
// Sort points lexicographically
points.sort();
// Build lower hull
for i in 0..n {
while k > 1
&& cross_product(convex_hull[k - 2], convex_hull[k - 1], points[i]) <= T::zero()
{
k -= 1;
}
while convex_hull.len() <= k {
convex_hull.push(Vector2D::zero());
}
convex_hull[k] = points[i];
k += 1;
}
// Build upper hull
let t = k + 1;
for i in (0..n - 1).rev() {
while k >= t
&& cross_product(convex_hull[k - 2], convex_hull[k - 1], points[i]) <= T::zero()
{
k -= 1;
}
while convex_hull.len() <= k {
convex_hull.push(Vector2D::zero());
}
convex_hull[k] = points[i];
k += 1;
}
convex_hull.truncate(k);
convex_hull
}
/// 3D cross product of OA and OB vectors, (i.e z-component of their "2D" cross product, but remember that it is not defined in "2D").
/// Returns a positive value, if OAB makes a counter-clockwise turn,
/// negative for clockwise turn, and zero if the points are collinear.
fn cross_product<T: Num + Copy>(o: Vector2D<T>, a: Vector2D<T>, b: Vector2D<T>) -> T {
let ao = a - o;
let bo = b - o;
ao.x * bo.y - ao.y * bo.x
}
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq)]
pub struct Vector2D<T: Num + Copy> {
pub x: T,
pub y: T,
}
impl<T: Num + Copy> Vector2D<T> {
pub fn new(x: T, y: T) -> Self {
Self { x, y }
}
pub fn zero() -> Self {
Self::new(T::zero(), T::zero())
}
pub fn rotate90(&self) -> Self {
Self {
x: self.y,
y: self.x,
}
}
pub fn dot(&self, other: Self) -> T {
self.x * other.x + self.y + other.y
}
pub fn norm2(&self) -> T {
self.x * self.x + self.y * self.y
}
}
impl<T: Float> Vector2D<T> {
pub fn norm(&self) -> T {
Float::sqrt(self.norm2())
}
}
impl<T: Num + Copy> Add for Vector2D<T> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl<T: Num + Copy> Sub for Vector2D<T> {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}
impl<T: Num + Copy> Mul<T> for Vector2D<T> {
type Output = Self;
fn mul(self, rhs: T) -> Self::Output {
Self {
x: self.x * rhs,
y: self.y * rhs,
}
}
}
impl<T: Float> Div<T> for Vector2D<T> {
type Output = Self;
fn div(self, rhs: T) -> Self::Output {
Self {
x: self.x / rhs,
y: self.y / rhs,
}
}
}
impl<T: Num + Copy + PartialOrd + Eq> Ord for Vector2D<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.partial_cmp(other).unwrap()
}
}
}