#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 { Real l = len(); return equal(l, 0) ? Vector() : *this/l; }
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