Skip to content

File Vector3D.h

File List > include > mesh > Vector3D.h

Go to the documentation of this file

#pragma once

#include <cmath>
#include <limits>
#include <stdexcept>

namespace Argos {
template <typename T> class Vector3D {
public:
  T x;
  T y;
  T z;

  Vector3D();

  Vector3D(T x, T y, T z);

  Vector3D operator+(const Vector3D &vector) const;

  Vector3D &operator+=(const Vector3D &vector);

  Vector3D operator-(const Vector3D &vector) const;

  Vector3D &operator-=(const Vector3D &vector);

  Vector3D operator*(const T &scal) const;

  Vector3D &operator*=(const T &scal);

  Vector3D operator/(const T &scal) const;

  Vector3D &operator/=(const T &scal);

  T operator*(const Vector3D &vector) const;

  Vector3D operator^(const Vector3D &vector) const;

  Vector3D &operator^=(const Vector3D &vector);

  bool operator==(const Vector3D &vector) const;

  bool operator!=(const Vector3D &vector) const;

  T norm() const;

  T normSquared() const;

  Vector3D normalized() const;
};

template <typename T>
std::ostream &operator<<(std::ostream &os, const Vector3D<T> &v) {
  os << v.x << " " << v.y << " " << v.z;
  return os;
}
} // namespace Argos

template <typename T> Argos::Vector3D<T>::Vector3D() {
  x = 0;
  y = 0;
  z = 0;
}

template <typename T> Argos::Vector3D<T>::Vector3D(T x, T y, T z) {
  this->x = x;
  this->y = y;
  this->z = z;
}

template <typename T>
Argos::Vector3D<T> Argos::Vector3D<T>::operator+(const Vector3D &vector) const {
  return Vector3D(this->x + vector.x, this->y + vector.y, this->z + vector.z);
}

template <typename T>
Argos::Vector3D<T> &Argos::Vector3D<T>::operator+=(const Vector3D &vector) {
  this->x += vector.x;
  this->y += vector.y;
  this->z += vector.z;

  return *this;
}

template <typename T>
Argos::Vector3D<T> Argos::Vector3D<T>::operator-(const Vector3D &vector) const {
  return Vector3D(this->x - vector.x, this->y - vector.y, this->z - vector.z);
}

template <typename T>
Argos::Vector3D<T> &Argos::Vector3D<T>::operator-=(const Vector3D &vector) {
  this->x -= vector.x;
  this->y -= vector.y;
  this->z -= vector.z;

  return *this;
}

template <typename T>
Argos::Vector3D<T> Argos::Vector3D<T>::operator*(const T &scal) const {
  return Vector3D(this->x * scal, this->y * scal, this->z * scal);
}

template <typename T>
Argos::Vector3D<T> &Argos::Vector3D<T>::operator*=(const T &scal) {
  this->x *= scal;
  this->y *= scal;
  this->z *= scal;

  return *this;
}

template <typename T>
Argos::Vector3D<T> Argos::Vector3D<T>::operator/(const T &scal) const {
  if (scal == 0) {
    throw std::overflow_error("Division by zero !");
  }

  return Vector3D(this->x / scal, this->y / scal, this->z / scal);
}

template <typename T>
Argos::Vector3D<T> Argos::Vector3D<T>::operator^(const Vector3D &vector) const {
  return Vector3D(this->y * vector.z - this->z * vector.y,
                  this->z * vector.x - this->x * vector.z,
                  this->x * vector.y - this->y * vector.x);
}

template <typename T>
Argos::Vector3D<T> &Argos::Vector3D<T>::operator/=(const T &scal) {
  if (scal == 0) {
    throw std::overflow_error("Division by zero !");
  }

  this->x /= scal;
  this->y /= scal;
  this->z /= scal;

  return *this;
}

template <typename T>
T Argos::Vector3D<T>::operator*(const Vector3D &vector) const {
  return this->x * vector.x + this->y * vector.y + this->z * vector.z;
}

template <typename T>
Argos::Vector3D<T> &Argos::Vector3D<T>::operator^=(const Vector3D &vector) {
  T x = this->y * vector.z - this->z * vector.y;
  T y = this->x * vector.z - this->z * vector.x;
  T z = this->x * vector.y - this->y * vector.x;

  this->x = x;
  this->y = y;
  this->z = z;

  return *this;
}

template <typename T>
bool Argos::Vector3D<T>::operator==(const Vector3D &vector) const {
  float epsilon = std::numeric_limits<T>::epsilon();
  return std::abs(this->x - vector.x) < epsilon &&
         std::abs(this->y - vector.y) < epsilon &&
         std::abs(this->z - vector.z) < epsilon;
}

template <typename T>
bool Argos::Vector3D<T>::operator!=(const Vector3D &vector) const {
  float epsilon = std::numeric_limits<T>::epsilon();
  return std::abs(this->x - vector.x) >= epsilon &&
         std::abs(this->y - vector.y) >= epsilon &&
         std::abs(this->z - vector.z) >= epsilon;
}

template <typename T> T Argos::Vector3D<T>::norm() const {
  return std::sqrt(x * x + y * y + z * z);
}

template <typename T> T Argos::Vector3D<T>::normSquared() const {
  return x * x + y * y + z * z;
}

template <typename T>
Argos::Vector3D<T> Argos::Vector3D<T>::normalized() const {
  return *this / this->norm();
}

namespace std {
template <> struct hash<Argos::Vector3D<double>> {
  std::size_t operator()(const Argos::Vector3D<double> &v) const {
    std::size_t h1 = std::hash<double>{}(v.x);
    std::size_t h2 = std::hash<double>{}(v.y);
    std::size_t h3 = std::hash<double>{}(v.z);

    h1 ^= h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2);
    h1 ^= h3 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2);

    return h1;
  }
};
} // namespace std