#include "Painter.h"

namespace Upp {

Pointf Xform2D::GetScaleXY() const
{
	return Pointf(sqrt(x.x * x.x + y.x * y.x), sqrt(x.y * x.y + y.y * y.y));
}

double Xform2D::GetScale() const
{
	Pointf d = GetScaleXY();
	return Length(d) / M_SQRT2;
}

inline bool Epsqual(double x, double y)
{
	return fabs(x - y) < 1e-10 * max(fabs(x), fabs(y));
}

bool Xform2D::IsRegular() const
{
	Pointf d = GetScaleXY();
	return Epsqual(d.x, d.y);
}

Xform2D::Xform2D()
{
	x.x = y.y = 1;
	x.y = y.x = t.x = t.y = 0;
}

Xform2D operator*(const Xform2D& a, const Xform2D& b)
{
	Xform2D r;
	r.x.x = a.x.x * b.x.x + a.y.x * b.x.y;
	r.x.y = a.x.y * b.x.x + a.y.y * b.x.y;
	r.y.x = a.x.x * b.y.x + a.y.x * b.y.y;
	r.y.y = a.x.y * b.y.x + a.y.y * b.y.y;
	r.t.x = a.t.x * b.x.x + a.t.y * b.x.y + b.t.x;
	r.t.y = a.t.x * b.y.x + a.t.y * b.y.y + b.t.y;
	return r;
}

Xform2D Xform2D::Translation(double x, double y)
{
	Xform2D m;
	m.t = Pointf(x, y);
	return m;
}

Xform2D Xform2D::Scale(double sx, double sy)
{
	Xform2D m;
	m.x.x = sx;
	m.y.y = sy;
	return m;
}

Xform2D Xform2D::Scale(double scale)
{
	return Scale(scale, scale);
}

Xform2D Xform2D::Rotation(double fi)
{
	double cosf = cos(fi);
	double sinf = sin(fi);
	Xform2D m;
	m.x.x = cosf;
	m.x.y = -sinf;
	m.y.x = sinf;
	m.y.y = cosf;
	m.t.x = m.t.y = 0;
	return m;
}

Xform2D Xform2D::Sheer(double fi)
{
	Xform2D m;
	m.x.y = atan(fi);
	return m;
}

Xform2D Xform2D::SheerX(double fi)
{
	Xform2D m;
	m.y.x = atan(fi);
	return m;
}

Xform2D Xform2D::Identity()
{
	Xform2D m;
	return m;
}

Xform2D Xform2D::Map(Pointf s1, Pointf s2, Pointf s3)
{
	Xform2D s;
	s.x.x = s1.x - s3.x;
	s.y.x = s1.y - s3.y;
	s.x.y = s2.x - s3.x;
	s.y.y = s2.y - s3.y;
	s.t = s3;
	return s;
}

Xform2D Xform2D::Map(Pointf s1, Pointf s2, Pointf s3, Pointf t1, Pointf t2, Pointf t3)
{
	return Inverse(Xform2D::Map(s1, s2, s3)) * Map(t1, t2, t3);
}

double  Determinant(const Xform2D& m)
{
	return m.x.x * m.y.y - m.y.x * m.x.y;
}

Xform2D Inverse(const Xform2D& m)
{
	Xform2D r;
	double det = Determinant(m);
	r.x = Pointf(m.y.y, -m.x.y) / det;
	r.y = Pointf(-m.y.x, m.x.x) / det;
	r.t.x = -m.t.x * r.x.x - m.t.y * r.x.y;
	r.t.y = -m.t.x * r.y.x - m.t.y * r.y.y;
	return r;
}

}
