powersasa 0.2.0

SASA and molecular volume computation using Power diagrams
Documentation
#pragma once

#include <cassert>
#include <cmath>
#include <cstddef>
#include <ostream>
#include <type_traits>

template <class T>
struct Vec3 {
  T data[3];

  constexpr Vec3() : data{T{}, T{}, T{}} {}
  constexpr Vec3(T x, T y, T z) : data{x, y, z} {}

  template <class U>
  constexpr explicit Vec3(const Vec3<U>& other)
      : data{static_cast<T>(other.x()), static_cast<T>(other.y()), static_cast<T>(other.z())} {}

  constexpr T& x() { return data[0]; }
  constexpr const T& x() const { return data[0]; }
  constexpr T& y() { return data[1]; }
  constexpr const T& y() const { return data[1]; }
  constexpr T& z() { return data[2]; }
  constexpr const T& z() const { return data[2]; }

  constexpr T& operator[](std::size_t i) {
    assert(i < 3);
    return data[i];
  }

  constexpr const T& operator[](std::size_t i) const {
    assert(i < 3);
    return data[i];
  }

  constexpr void setZero() { data[0] = data[1] = data[2] = T{}; }

  constexpr Vec3 operator+() const { return *this; }
  constexpr Vec3 operator-() const { return Vec3(-data[0], -data[1], -data[2]); }

  constexpr Vec3& operator+=(const Vec3& rhs) {
    data[0] += rhs.data[0];
    data[1] += rhs.data[1];
    data[2] += rhs.data[2];
    return *this;
  }

  constexpr Vec3& operator-=(const Vec3& rhs) {
    data[0] -= rhs.data[0];
    data[1] -= rhs.data[1];
    data[2] -= rhs.data[2];
    return *this;
  }

  template <class U, std::enable_if_t<std::is_arithmetic_v<U>, int> = 0>
  constexpr Vec3& operator*=(const U& scalar) {
    const T s = static_cast<T>(scalar);
    data[0] *= s;
    data[1] *= s;
    data[2] *= s;
    return *this;
  }

  template <class U, std::enable_if_t<std::is_arithmetic_v<U>, int> = 0>
  constexpr Vec3& operator/=(const U& scalar) {
    const T s = static_cast<T>(scalar);
    data[0] /= s;
    data[1] /= s;
    data[2] /= s;
    return *this;
  }

  constexpr T dot(const Vec3& rhs) const {
    return data[0] * rhs.data[0] + data[1] * rhs.data[1] + data[2] * rhs.data[2];
  }

  constexpr Vec3 cross(const Vec3& rhs) const {
    return Vec3(data[1] * rhs.data[2] - data[2] * rhs.data[1],
                data[2] * rhs.data[0] - data[0] * rhs.data[2],
                data[0] * rhs.data[1] - data[1] * rhs.data[0]);
  }

  constexpr T squaredNorm() const { return dot(*this); }

  T norm() const { return static_cast<T>(std::sqrt(squaredNorm())); }
};

template <class T>
constexpr Vec3<T> operator+(Vec3<T> lhs, const Vec3<T>& rhs) {
  lhs += rhs;
  return lhs;
}

template <class T>
constexpr Vec3<T> operator-(Vec3<T> lhs, const Vec3<T>& rhs) {
  lhs -= rhs;
  return lhs;
}

template <class T, class U, std::enable_if_t<std::is_arithmetic_v<U>, int> = 0>
constexpr Vec3<T> operator*(Vec3<T> lhs, const U& scalar) {
  lhs *= scalar;
  return lhs;
}

template <class U, class T, std::enable_if_t<std::is_arithmetic_v<U>, int> = 0>
constexpr Vec3<T> operator*(const U& scalar, Vec3<T> rhs) {
  rhs *= scalar;
  return rhs;
}

template <class T, class U, std::enable_if_t<std::is_arithmetic_v<U>, int> = 0>
constexpr Vec3<T> operator/(Vec3<T> lhs, const U& scalar) {
  lhs /= scalar;
  return lhs;
}

template <class T>
inline std::ostream& operator<<(std::ostream& os, const Vec3<T>& v) {
  os << v.x() << ' ' << v.y() << ' ' << v.z();
  return os;
}