Documentation
use std::f64::{NEG_INFINITY,INFINITY};
use std::ops::{Add,AddAssign,Sub,SubAssign,Mul};
use serde::{Serialize,Deserialize};

#[derive(Debug,Copy,Clone,Serialize,Deserialize)]
pub struct Point {
    pub x:f64,
    pub y:f64
}

#[derive(Debug,Copy,Clone,Serialize,Deserialize)]
pub struct Rectangle {
    pub a:Point,
    pub b:Point
}

impl From<(f64,f64)> for Point {
    fn from((x,y):(f64,f64))->Self {
	Point{ x, y }
    }
}

pub const ORIGIN : Point = Point{ x:0.0,y:0.0 };

pub fn point(x:f64,y:f64)->Point {
    Point{ x, y }
}

pub fn rectangle(p1:Point,p2:Point)->Rectangle {
    Rectangle{ a:p1.min(p2), b:p1.max(p2) }
}

impl Rectangle {
    pub fn add_point(&mut self,p:Point) {
	self.a = self.a.min(p);
	self.b = self.b.max(p);
    }

    pub fn add_rectangle(&mut self,r:Rectangle) {
	self.add_point(r.a);
	self.add_point(r.b);
    }

    pub fn dx(&self)->f64 {
	self.b.x - self.a.x
    }

    pub fn dy(&self)->f64 {
	self.b.y - self.a.y
    }

    pub fn all()->Self {
	Rectangle{
	    a:point(NEG_INFINITY,NEG_INFINITY),
	    b:point(INFINITY,INFINITY)
	}
    }

    pub fn empty()->Self {
	Rectangle{
	    a:point(INFINITY,INFINITY),
	    b:point(NEG_INFINITY,NEG_INFINITY)
	}
    }

    pub fn bounding(pts:&[Point])->Rectangle {
	pts.iter().fold(Self::all(),|mut r,&p| { r.add_point(p); r })
    }
}

impl Point {
    pub fn with_x(&self,other:Self)->Self {
	point(other.x,self.y)
    }

    pub fn with_y(&self,other:Self)->Self {
	point(self.x,other.y)
    }

    pub fn max(self,other:Self)->Self {
	point(self.x.max(other.x),self.y.max(other.y))
    }

    pub fn min(self,other:Self)->Self {
	point(self.x.min(other.x),self.y.min(other.y))
    }

    pub fn as_pair(&self)->(f64,f64) {
	(self.x,self.y)
    }

    pub fn norm(self)->f64 {
	self.x.hypot(self.y)
    }

    pub fn normalize(self)->Self {
	let n = self.norm();
	point(self.x/n,self.y/n)
    }
}

impl SubAssign<Point> for Point {
    fn sub_assign(&mut self,other:Self) {
	self.x -= other.x;
	self.y -= other.y;
    }
}

impl Sub<Point> for Point {
    type Output = Point;

    fn sub(self,other:Self)->Self {
	point(self.x - other.x,self.y - other.y)
    }
}

impl AddAssign<Point> for Point {
    fn add_assign(&mut self,other:Self) {
	self.x += other.x;
	self.y += other.y;
    }
}

impl Add<Point> for Point {
    type Output = Point;

    fn add(self,other:Self)->Self {
	point(self.x + other.x,self.y + other.y)
    }
}

impl Mul<Point> for f64 {
    type Output = Point;

    fn mul(self,other:Point)->Point {
	point(self * other.x,self * other.y)
    }
}

impl Add<(f64,f64)> for Point {
    type Output = Point;

    fn add(self,(x,y):(f64,f64))->Self {
	point(self.x + x,self.y + y)
    }
}

impl AddAssign<(f64,f64)> for Point {
    fn add_assign(&mut self,other:(f64,f64)) {
	self.x += other.0;
	self.y += other.1;
    }
}

impl Sub<(f64,f64)> for Point {
    type Output = Point;

    fn sub(self,(x,y):(f64,f64))->Self {
	point(self.x - x,self.y - y)
    }
}

impl SubAssign<(f64,f64)> for Point {
    fn sub_assign(&mut self,other:(f64,f64)) {
	self.x -= other.0;
	self.y -= other.1;
    }
}