Blob Blame Raw
#ifndef VECTOR_H
#define VECTOR_H


#include <cmath>

#include <algorithm>

#include "real.h"


class Vector {
public:
	union {
		struct { Real x, y; };
		struct { Real coords[2]; };
	};
	
	explicit Vector(const Real &x = Real(), const Real &y = Real()): x(x), y(y) { }
	
	const Real& operator[] (int i) const { return coords[i]; }
	Real& operator[] (int i) { return coords[i]; }

	bool operator<(const Vector &a) const { return less(x, a.x) || (!less(a.x, x) && less(y, a.y)); }
	bool operator==(const Vector &a) const { return equal(x, a.x) && equal(y, a.y); }
	bool operator!=(const Vector &a) const { return !(*this == a); }

	Vector operator-() const { return Vector(-x, -y); }
	
	Vector operator+(const Vector &a) const { return Vector(x + a.x, y + a.y); }
	Vector operator-(const Vector &a) const { return Vector(x - a.x, y - a.y); }
	Vector operator*(const Real &a) const { return Vector(x*a, y*a); }
	Vector operator/(const Real &a) const { return *this * (Real(1)/a); }
	
	Vector& operator+=(const Vector &a) { x += a.x; y += a.y; return *this; }
	Vector& operator-=(const Vector &a) { x -= a.x; y -= a.y; return *this; }
	Vector& operator*=(const Real &a) { x *= a; y *= a; return *this; }
	Vector& operator/=(const Real &a) { return *this *= (Real(1)/a); }

	friend inline Vector operator*(const Real &a, const Vector &b) { return b*a; }
	friend inline Real dot(const Vector &a, const Vector &b) { return a.x*b.x + a.y*b.y; }

	bool iszero() const { return *this == Vector(); }
	void reset() { *this = Vector(); }

	Real lensqr() const { return dot(*this, *this); }
	Real len() const { return sqrt(lensqr()); }

	Vector norm() const { return iszero() ? Vector() : *this/len(); }
	Vector perp() const { return Vector(-y, x); }
	Vector scale(const Vector &a) const { return Vector(x*a.x, y*a.y); }
	Vector rotate(const Real &angle) const {
		Vector a = from_angle(angle);
		return Vector(x*a.x - y*a.y, x*a.y + y*a.x);
	}
	
	static Vector from_angle(Real angle)
		{ return Vector(cos(angle), sin(angle)); }
};


class RealPair {
public:
	Real a0, a1;
	RealPair(const Real &a0, const Real &a1):
		a0(a0), a1(a1) { }
	explicit RealPair(const Real &a = Real()):
		RealPair(a, a) { }
	Real dist() const { return a1 - a0; }
	void reset() { a0 = a1 = Real(); }
};


class Range: public RealPair {
public:
	using RealPair::RealPair;
	Real size() const { return dist(); }
	bool isempty() const { return !less(a0, a1); }
	Range& expand(const Real &a) {
		if (a < a0) a0 = a;
		if (a1 < a) a1 = a;
		return *this;
	}
	Range get_expanded(const Real &a) const
		{ return Range(std::min(a, a0), std::max(a1, a)); }
};


class VectorPair {
public:
	Real x0, y0, x1, y1;
	
	VectorPair(const Real &x0, const Real &y0, const Real &x1, const Real &y1):
		x0(x0), y0(y0), x1(x1), y1(y1) { }
	explicit VectorPair(const Real &x = Real(), const Real &y = Real()):
		VectorPair(x, y, x, y) { }

	VectorPair(const Vector &p0, const Vector &p1):
		VectorPair(p0.x, p0.y, p1.x, p1.y) { }
	explicit VectorPair(const Vector &p):
		VectorPair(p, p) { }

	VectorPair(const RealPair &x, const RealPair &y):
		VectorPair(x.a0, y.a0, x.a1, y.a1) { }

	Vector& p0() { return *(Vector*)&x0; };
	Vector& p1() { return *(Vector*)&x1; };
	const Vector& p0() const { return *(const Vector*)&x0; };
	const Vector& p1() const { return *(const Vector*)&x1; };
	
	Vector dist() const { return p1() - p0(); }
	Real dist_x() const { return x1 - x0; }
	Real dist_y() const { return y1 - y0; }
	
	void reset() { p0().reset(); p1().reset(); }
};


class Rect: public VectorPair {
public:
	using VectorPair::VectorPair;
	
	Vector size() const { return dist(); }
	Real width() const { return dist_x(); }
	Real height() const { return dist_y(); }
	
	bool isempty() const { return !less(x0, x1) || !less(y0, y1); }
	
	Rect& expand(const Real &x, const Real &y) {
		if (x0 < x) x0 = x;
		if (y0 < y) y0 = y;
		if (x1 < x) x1 = x;
		if (y1 < y) y1 = y;
		return *this;
	}
	Rect& expand(const Vector &p)
		{ return expand(p.x, p.y); }

	Rect get_expanded(const Real &x, const Real &y) const
		{ return Rect(std::min(x0, x), std::min(y0, y), std::max(x1, x), std::max(y1, y)); }
	Rect get_expanded(const Vector &p) const
		{ return get_expanded(p.x, p.y); }
};


#endif