Documentation
use beambook::geometry::{point,Point};

#[derive(Copy,Clone,Debug)]
pub struct Homography {
    coefs:[[f64;3];3]
}

impl Homography {
    pub fn id()->Self {
	Self{ coefs:[[1.0,0.0,0.0],
		     [0.0,1.0,0.0],
		     [0.0,0.0,1.0]] }
    }

    pub fn rotation(theta:f64)->Self {
	Self{ coefs:[[ theta.cos(),theta.sin(),0.0],
		     [-theta.sin(),theta.cos(),0.0],
		     [         0.0,        0.0,1.0]] }
    }

    pub fn scaling(s:f64)->Self {
	Self{ coefs:[[1.0,0.0,0.0],
		     [0.0,1.0,0.0],
		     [0.0,0.0,1.0/s]] }
    }

    pub fn translation(p:Point)->Self {
	Self{ coefs:[[1.0,0.0,p.x],
		     [0.0,1.0,p.y],
		     [0.0,0.0,1.0]] }
    }

    pub fn apply(&self,p:Point)->Point {
	let [[a,b,c],[d,e,f],[g,h,i]] = self.coefs;
	let Point{ x,y } = p;
	let z = 1.0;
	let xp = a*x+b*y+c*z;
	let yp = d*x+e*y+f*z;
	let zp = g*x+h*y+i*z;
	point(xp/zp,yp/zp)
    }

    pub fn compose(&self,other:Self)->Self {
	let [[a1,b1,c1],[d1,e1,f1],[g1,h1,i1]] = self.coefs;
	let [[a2,b2,c2],[d2,e2,f2],[g2,h2,i2]] = other.coefs;
	Self{ coefs:[[a1*a2+b1*d2+c1*g2,
		      a1*b2+b1*e2+c1*h2,
		      a1*c2+b1*f2+c1*i2],
		     [d1*a2+e1*d2+f1*g2,
		      d1*b2+e1*e2+f1*h2,
		      d1*c2+e1*f2+f1*i2],
		     [g1*a2+h1*d2+i1*g2,
		      g1*b2+h1*e2+i1*h2,
		      g1*c2+h1*f2+i1*i2]] }
    }
}