#include "Plane.hpp"

Plane::Plane(
  const Vector& n,
  const Vector& o
) {
  set(
    n,
    o
  );
}

Plane& Plane::set(
  const Vector& n,
  const Vector& o
) {
  a = n.x;
  b = n.y;
  c = n.z;
  d = - (a * o.x + b * o.y + c * o.z);
  return *this;
}

Plane& Plane::set(const Line& l) {
  return set(
    l.getNormal(),
    l.getOrigin()
  );
}

const Vector& Plane::getNormal() const {
  static Vector ret;
  return ret.set(
    a,
    b,
    c
  );
}

const double Plane::getDistance(const Vector& v) const {
  return a * v.x + b * v.y + c * v.z + d;
}

const Vector& Plane::getCrossing(const Line& l) const {
  const Vector& o = l.getOrigin();
  const Vector& n = l.getNormal();
  const double ro =
    (a * o.x + b * o.y + c * o.z + d) /
    (a * n.x + b * n.y + c * n.z);
  static Vector ret;
  return ret.set(
    o.x - n.x * ro,
    o.y - n.y * ro,
    o.z - n.z * ro
  );
}

const double Plane::getSin(const Line& l) const {
  return getNormal().getSin(
    l.getNormal()
  );
}

Plane& Plane::operator *= (const Matrix& m) {
  return *this;
}

const Plane Plane::XY = Plane(Vector::Z);
const Plane Plane::XZ = Plane(Vector::Y);
const Plane Plane::YZ = Plane(Vector::X);

const Vector& Plane::getProjection(const Vector& v) const {
  static Line l;
  return getCrossing(
    l.set(
      getNormal(),
      v
    )
  );
}

const bool Plane::isFront(const Vector& v) const {
  return getDistance(v) >= 0;
}

const bool Plane::isBack(const Vector& v) const {
  return getDistance(v) <= 0;
}
