Refactor vec, add domain-specific types (world, window, tile)
This commit is contained in:
parent
92b36a8943
commit
47977d9979
@ -5,6 +5,7 @@
|
|||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
#include "math.hpp"
|
#include "math.hpp"
|
||||||
#include "sprite.hpp"
|
#include "sprite.hpp"
|
||||||
|
#include "coorginates.hpp"
|
||||||
|
|
||||||
Entity::Entity(WorldPos position) : m_Position(position) {
|
Entity::Entity(WorldPos position) : m_Position(position) {
|
||||||
LOG_DEBUG("spawning entity at position ", position);
|
LOG_DEBUG("spawning entity at position ", position);
|
||||||
@ -25,13 +26,13 @@ void Entity::ZeroActualVelocityInDirection(WorldPos direction) {
|
|||||||
// where e1 is formed by the direction where we want to zero-out
|
// where e1 is formed by the direction where we want to zero-out
|
||||||
// the velocity, and e2 is the orthogonal vector.
|
// the velocity, and e2 is the orthogonal vector.
|
||||||
// Scalars q1, q2 are coordinates for e1, e2 basis.
|
// Scalars q1, q2 are coordinates for e1, e2 basis.
|
||||||
WorldPos e1 = direction.normalized();
|
WorldPos e1 = direction.GetNormalized();
|
||||||
WorldPos e2 = e1.orthogonal();
|
WorldPos e2 = e1.GetOrthogonal();
|
||||||
|
|
||||||
// q1 * e1 + q2 * e2 = v, from this follows:
|
// q1 * e1 + q2 * e2 = v, from this follows:
|
||||||
auto &v = GetActualVelocity();
|
auto &v = GetActualVelocity();
|
||||||
float q2 = (v.y * e1.x - v.x * e1.y) / (e2.y * e1.x - e2.x * e1.y);
|
float q2 = (v.y() * e1.x() - v.x() * e1.y()) / (e2.y() * e1.x() - e2.x() * e1.y());
|
||||||
float q1 = (v.x - q2 * e2.x) / e1.x;
|
float q1 = (v.x() - q2 * e2.x()) / e1.x();
|
||||||
|
|
||||||
// We then zero-out the q1, but only if it's positive - meaning
|
// We then zero-out the q1, but only if it's positive - meaning
|
||||||
// it is aiming in the direction of "direction", not out.
|
// it is aiming in the direction of "direction", not out.
|
||||||
|
441
cpp/src/math.hpp
441
cpp/src/math.hpp
@ -1,21 +1,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <concepts>
|
#include <concepts>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <utility>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <ranges>
|
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <ranges>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
requires std::floating_point<T>
|
requires std::floating_point<T>
|
||||||
static inline bool equalEpsilon(const T& a, const T& b)
|
static inline bool equalEpsilon(const T &a, const T &b) {
|
||||||
{
|
constexpr auto epsilon = []() {
|
||||||
constexpr auto epsilon = [](){
|
|
||||||
if constexpr (std::is_same_v<T, float>) {
|
if constexpr (std::is_same_v<T, float>) {
|
||||||
return T{1e-5};
|
return T{1e-5};
|
||||||
} else {
|
} else {
|
||||||
@ -29,46 +27,41 @@ static inline bool equalEpsilon(const T& a, const T& b)
|
|||||||
return std::abs(a - b) < epsilon;
|
return std::abs(a - b) < epsilon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Any {};
|
||||||
|
|
||||||
template <typename T, size_t N>
|
template <typename T, size_t N, typename Tag = Any> class vec {
|
||||||
class vec {
|
|
||||||
public:
|
public:
|
||||||
vec() : m_Array{} {}
|
vec() : m_Array{} {}
|
||||||
|
|
||||||
template <typename... ArgsT>
|
template <typename... ArgsT>
|
||||||
requires (std::same_as<ArgsT, T> && ...) && (sizeof...(ArgsT) == N)
|
requires(std::same_as<ArgsT, T> && ...) && (sizeof...(ArgsT) == N)
|
||||||
vec(ArgsT... args) : m_Array{args...} {}
|
vec(ArgsT... args) : m_Array{args...} {}
|
||||||
|
|
||||||
const T& operator[](size_t index) const
|
const T &operator[](size_t index) const {
|
||||||
{
|
|
||||||
// we leave run-time checks to the underlying std::array
|
// we leave run-time checks to the underlying std::array
|
||||||
return m_Array[index];
|
return m_Array[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
T& operator[](size_t index)
|
T &operator[](size_t index) {
|
||||||
{
|
|
||||||
// we leave run-time checks to the underlying std::array
|
// we leave run-time checks to the underlying std::array
|
||||||
return m_Array[index];
|
return m_Array[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
friend std::ostream &operator<<(std::ostream &os, const vec &obj)
|
friend std::ostream &operator<<(std::ostream &os, const vec &obj) {
|
||||||
{
|
|
||||||
os << "( ";
|
os << "( ";
|
||||||
for (const auto& element : obj.m_Array) {
|
for (const auto &element : obj.m_Array) {
|
||||||
os << element << " ";
|
os << element << " ";
|
||||||
}
|
}
|
||||||
os << ")";
|
os << ")";
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// binary operators
|
// binary operators
|
||||||
//
|
//
|
||||||
|
|
||||||
friend bool operator==(const vec& a, const vec& b)
|
friend bool operator==(const vec &a, const vec &b) {
|
||||||
{
|
for (const auto &[u, v] : std::views::zip(a.m_Array, b.m_Array)) {
|
||||||
for (const auto& [u, v] : std::views::zip(a.m_Array,b.m_Array)) {
|
|
||||||
if (!equalEpsilon(u, v)) {
|
if (!equalEpsilon(u, v)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -76,40 +69,35 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator!=(const vec& a, const vec& b)
|
friend bool operator!=(const vec &a, const vec &b) { return !(a == b); }
|
||||||
{
|
|
||||||
return !(a == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend vec operator+(const vec& a, const vec& b)
|
friend vec operator+(const vec &a, const vec &b) {
|
||||||
{
|
vec<T, N> c;
|
||||||
vec<T,N> c;
|
std::ranges::transform(a.m_Array, b.m_Array, c.m_Array.begin(),
|
||||||
std::ranges::transform(a.m_Array, b.m_Array, c.m_Array.begin(), std::plus{});
|
std::plus{});
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend vec operator-(const vec& a, const vec& b)
|
friend vec operator-(const vec &a, const vec &b) {
|
||||||
{
|
vec<T, N> c;
|
||||||
vec<T,N> c;
|
std::ranges::transform(a.m_Array, b.m_Array, c.m_Array.begin(),
|
||||||
std::ranges::transform(a.m_Array, b.m_Array, c.m_Array.begin(), std::minus{});
|
std::minus{});
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend vec operator*(const vec& a, const T& scalar)
|
friend vec operator*(const vec &a, const T &scalar) {
|
||||||
{
|
vec<T, N> c;
|
||||||
vec<T,N> c;
|
std::ranges::transform(a.m_Array, std::views::repeat(scalar),
|
||||||
std::ranges::transform(a.m_Array, std::views::repeat(scalar), c.m_Array.begin(), std::multiplies{});
|
c.m_Array.begin(), std::multiplies{});
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend vec operator*(const T& scalar, const vec& a) {
|
friend vec operator*(const T &scalar, const vec &a) { return a * scalar; }
|
||||||
return a * scalar;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend vec operator/(const vec& a, const T& scalar)
|
friend vec operator/(const vec &a, const T &scalar) {
|
||||||
{
|
vec<T, N> c;
|
||||||
vec<T,N> c;
|
std::ranges::transform(a.m_Array, std::views::repeat(scalar),
|
||||||
std::ranges::transform(a.m_Array, std::views::repeat(scalar), c.m_Array.begin(), std::divides{});
|
c.m_Array.begin(), std::divides{});
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,44 +105,33 @@ public:
|
|||||||
// compound-assignment operators
|
// compound-assignment operators
|
||||||
//
|
//
|
||||||
|
|
||||||
vec& operator+=(const vec& b)
|
vec &operator+=(const vec &b) {
|
||||||
{
|
vec &a = *this;
|
||||||
vec& a = *this;
|
std::ranges::transform(a.m_Array, b.m_Array, a.m_Array.begin(),
|
||||||
std::ranges::transform(a.m_Array, b.m_Array, a.m_Array.begin(), std::plus{});
|
std::plus{});
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec& operator-=(const vec& b)
|
vec &operator-=(const vec &b) {
|
||||||
{
|
vec &a = *this;
|
||||||
vec& a = *this;
|
std::ranges::transform(a.m_Array, b.m_Array, a.m_Array.begin(),
|
||||||
std::ranges::transform(a.m_Array, b.m_Array, a.m_Array.begin(), std::minus{});
|
std::minus{});
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Utility functions
|
// Utility functions
|
||||||
//
|
//
|
||||||
|
|
||||||
T LengthSquared() const
|
T LengthSquared() const {
|
||||||
{
|
return std::transform_reduce(m_Array.begin(), m_Array.end(), T{0.0},
|
||||||
return std::transform_reduce(
|
std::plus{}, [](T x) { return x * x; });
|
||||||
m_Array.begin(), m_Array.end(),
|
|
||||||
T{0.0},
|
|
||||||
std::plus{},
|
|
||||||
[](T x){
|
|
||||||
return x*x;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
T Length() const
|
T Length() const { return std::sqrt(LengthSquared()); }
|
||||||
{
|
|
||||||
return std::sqrt(LengthSquared());
|
|
||||||
}
|
|
||||||
|
|
||||||
T DistanceTo(const vec& b) const {
|
T DistanceTo(const vec &b) const {
|
||||||
const vec& a = *this;
|
const vec &a = *this;
|
||||||
return (a - b).Length();
|
return (a - b).Length();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,27 +139,26 @@ public:
|
|||||||
// In-place vector operations
|
// In-place vector operations
|
||||||
//
|
//
|
||||||
|
|
||||||
void Normalize()
|
void Normalize() {
|
||||||
{
|
|
||||||
T length = Length();
|
T length = Length();
|
||||||
if (equalEpsilon(length, T{0}))
|
if (equalEpsilon(length, T{0}))
|
||||||
return;
|
return;
|
||||||
std::ranges::transform(m_Array, std::views::repeat(length), m_Array.begin(), std::divides{});
|
std::ranges::transform(m_Array, std::views::repeat(length), m_Array.begin(),
|
||||||
|
std::divides{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Methods returning new object
|
// Methods returning new object
|
||||||
//
|
//
|
||||||
|
|
||||||
vec GetNormalized() const
|
vec GetNormalized() const {
|
||||||
{
|
|
||||||
vec tmp = *this;
|
vec tmp = *this;
|
||||||
tmp.Normalize();
|
tmp.Normalize();
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec GetOrthogonal() const requires (N == 2)
|
vec GetOrthogonal() const
|
||||||
|
requires(N == 2)
|
||||||
{
|
{
|
||||||
vec tmp = *this;
|
vec tmp = *this;
|
||||||
|
|
||||||
@ -192,15 +168,53 @@ public:
|
|||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const T& x = m_Array[0];
|
//
|
||||||
// const T& y = m_Array[1];
|
// Helpers
|
||||||
// const T& z = m_Array[2];
|
//
|
||||||
|
|
||||||
|
const T &x() const
|
||||||
|
requires(N >= 1)
|
||||||
|
{
|
||||||
|
return m_Array[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
T &x()
|
||||||
|
requires(N >= 1)
|
||||||
|
{
|
||||||
|
return m_Array[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
const T &y() const
|
||||||
|
requires(N >= 2)
|
||||||
|
{
|
||||||
|
return m_Array[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
T &y()
|
||||||
|
requires(N >= 2)
|
||||||
|
{
|
||||||
|
return m_Array[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const T &z() const
|
||||||
|
requires(N >= 3)
|
||||||
|
{
|
||||||
|
return m_Array[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
T &z()
|
||||||
|
requires(N >= 3)
|
||||||
|
{
|
||||||
|
return m_Array[2];
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<T,N> m_Array;
|
std::array<T, N> m_Array;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Aliases
|
||||||
|
//
|
||||||
|
|
||||||
using vec2 = vec<float, 2>;
|
using vec2 = vec<float, 2>;
|
||||||
using vec3 = vec<float, 3>;
|
using vec3 = vec<float, 3>;
|
||||||
@ -215,138 +229,143 @@ using uvec2 = vec<std::uint32_t, 2>;
|
|||||||
using uvec3 = vec<std::uint32_t, 3>;
|
using uvec3 = vec<std::uint32_t, 3>;
|
||||||
using uvec4 = vec<std::uint32_t, 4>;
|
using uvec4 = vec<std::uint32_t, 4>;
|
||||||
|
|
||||||
constexpr double EQUALITY_LIMIT = 1e-6;
|
// tags for differentiating between domains
|
||||||
|
struct WorldTag {};
|
||||||
|
struct WindowTag {};
|
||||||
|
struct TileTag {};
|
||||||
|
|
||||||
#ifdef _WIN32
|
// types for each domain
|
||||||
#include <numbers>
|
using WorldPos = vec<float, 2, WorldTag>;
|
||||||
#define M_PI std::numbers::pi
|
using WindowPos = vec<float, 2, WindowTag>;
|
||||||
#endif
|
using TilePos = vec<int32_t, 2, WindowTag>;
|
||||||
|
|
||||||
template <typename T> struct Vec2D {
|
//
|
||||||
public:
|
// Utils
|
||||||
Vec2D() = default;
|
//
|
||||||
~Vec2D() = default;
|
|
||||||
|
|
||||||
template <typename U>
|
|
||||||
Vec2D(Vec2D<U> other) {
|
|
||||||
this->x = static_cast<T>(other.x);
|
|
||||||
this->y = static_cast<T>(other.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2D& operator+=(const Vec2D &other) {
|
|
||||||
x += other.x;
|
|
||||||
y += other.y;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename U>
|
|
||||||
requires std::is_arithmetic_v<U>
|
|
||||||
Vec2D& operator/=(U k) {
|
|
||||||
this->x /= static_cast<T>(k);
|
|
||||||
this->y /= static_cast<T>(k);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend Vec2D operator+(const Vec2D &a, const Vec2D &b) {
|
|
||||||
return Vec2D{a.x + b.x, a.y + b.y};
|
|
||||||
}
|
|
||||||
|
|
||||||
friend Vec2D operator-(const Vec2D &a, const Vec2D &b) {
|
|
||||||
return Vec2D{a.x - b.x, a.y - b.y};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename U>
|
|
||||||
requires std::is_arithmetic_v<U>
|
|
||||||
friend Vec2D operator*(U k, const Vec2D &v)
|
|
||||||
{
|
|
||||||
return Vec2D{k * v.x, k * v.y};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename U>
|
|
||||||
requires std::is_arithmetic_v<U>
|
|
||||||
friend Vec2D operator/(const Vec2D &v, U k)
|
|
||||||
{
|
|
||||||
return Vec2D{v.x / k, v.y / k};
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator==(const Vec2D &a, const Vec2D &b) {
|
|
||||||
if constexpr (std::is_integral_v<T>) {
|
|
||||||
return a.x == b.x && a.y == b.y;
|
|
||||||
} else if constexpr (std::is_floating_point_v<T>) {
|
|
||||||
return a.distance(b) < EQUALITY_LIMIT;
|
|
||||||
} else {
|
|
||||||
static_assert("Unhandled comparison");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2D operator*(float b) const { return Vec2D{b * x, b * y}; }
|
|
||||||
|
|
||||||
T distance_squared(const Vec2D &other) const {
|
|
||||||
T dx = x - other.x;
|
|
||||||
T dy = y - other.y;
|
|
||||||
return dx * dx + dy * dy;
|
|
||||||
}
|
|
||||||
|
|
||||||
T distance(const Vec2D &other) const
|
|
||||||
requires std::floating_point<T>
|
|
||||||
{
|
|
||||||
return sqrt(distance_squared(other));
|
|
||||||
}
|
|
||||||
|
|
||||||
void normalize()
|
|
||||||
requires std::floating_point<T>
|
|
||||||
{
|
|
||||||
auto length = sqrt(x * x + y * y);
|
|
||||||
if (length < EQUALITY_LIMIT) {
|
|
||||||
x = y = 0;
|
|
||||||
} else {
|
|
||||||
x /= length;
|
|
||||||
y /= length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2D normalized()
|
|
||||||
requires std::floating_point<T>
|
|
||||||
{
|
|
||||||
Vec2D v(*this);
|
|
||||||
v.normalize();
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2D orthogonal() const
|
|
||||||
{
|
|
||||||
Vec2D v(*this);
|
|
||||||
|
|
||||||
std::swap(v.x, v.y);
|
|
||||||
v.x = -v.x;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename U> Vec2D(std::initializer_list<U> list) {
|
|
||||||
assert(list.size() == 2);
|
|
||||||
auto first_element = *list.begin();
|
|
||||||
auto second_element = *(list.begin() + 1);
|
|
||||||
x = static_cast<T>(first_element);
|
|
||||||
y = static_cast<T>(second_element);
|
|
||||||
}
|
|
||||||
|
|
||||||
T x, y;
|
|
||||||
|
|
||||||
friend std::ostream &operator<<(std::ostream &os, const Vec2D &obj) {
|
|
||||||
os << "( " << obj.x << ", " << obj.y << ")";
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using TilePos = Vec2D<int>;
|
|
||||||
using WorldPos = Vec2D<float>;
|
|
||||||
using WindowPos = Vec2D<float>;
|
|
||||||
|
|
||||||
struct TilePosHash {
|
struct TilePosHash {
|
||||||
std::size_t operator()(const TilePos& p) const noexcept {
|
std::size_t operator()(const TilePos &p) const noexcept {
|
||||||
std::size_t h1 = std::hash<int>{}(p.x);
|
std::size_t h1 = std::hash<int>{}(p.x());
|
||||||
std::size_t h2 = std::hash<int>{}(p.y);
|
std::size_t h2 = std::hash<int>{}(p.y());
|
||||||
return h1 ^ (h2 + 0x9e3779b9 + (h1<<6) + (h1>>2));
|
return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// old stuff - TODO delete
|
||||||
|
|
||||||
|
// constexpr double EQUALITY_LIMIT = 1e-6;
|
||||||
|
// template <typename T> struct Vec2D {
|
||||||
|
// public:
|
||||||
|
// Vec2D() = default;
|
||||||
|
// ~Vec2D() = default;
|
||||||
|
//
|
||||||
|
// template <typename U>
|
||||||
|
// Vec2D(Vec2D<U> other) {
|
||||||
|
// this->x = static_cast<T>(other.x);
|
||||||
|
// this->y = static_cast<T>(other.y);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Vec2D& operator+=(const Vec2D &other) {
|
||||||
|
// x += other.x;
|
||||||
|
// y += other.y;
|
||||||
|
// return *this;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// template <typename U>
|
||||||
|
// requires std::is_arithmetic_v<U>
|
||||||
|
// Vec2D& operator/=(U k) {
|
||||||
|
// this->x /= static_cast<T>(k);
|
||||||
|
// this->y /= static_cast<T>(k);
|
||||||
|
// return *this;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// friend Vec2D operator+(const Vec2D &a, const Vec2D &b) {
|
||||||
|
// return Vec2D{a.x + b.x, a.y + b.y};
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// friend Vec2D operator-(const Vec2D &a, const Vec2D &b) {
|
||||||
|
// return Vec2D{a.x - b.x, a.y - b.y};
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// template <typename U>
|
||||||
|
// requires std::is_arithmetic_v<U>
|
||||||
|
// friend Vec2D operator*(U k, const Vec2D &v)
|
||||||
|
// {
|
||||||
|
// return Vec2D{k * v.x, k * v.y};
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// template <typename U>
|
||||||
|
// requires std::is_arithmetic_v<U>
|
||||||
|
// friend Vec2D operator/(const Vec2D &v, U k)
|
||||||
|
// {
|
||||||
|
// return Vec2D{v.x / k, v.y / k};
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// friend bool operator==(const Vec2D &a, const Vec2D &b) {
|
||||||
|
// if constexpr (std::is_integral_v<T>) {
|
||||||
|
// return a.x == b.x && a.y == b.y;
|
||||||
|
// } else if constexpr (std::is_floating_point_v<T>) {
|
||||||
|
// return a.distance(b) < EQUALITY_LIMIT;
|
||||||
|
// } else {
|
||||||
|
// static_assert("Unhandled comparison");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Vec2D operator*(float b) const { return Vec2D{b * x, b * y}; }
|
||||||
|
//
|
||||||
|
// T distance_squared(const Vec2D &other) const {
|
||||||
|
// T dx = x - other.x;
|
||||||
|
// T dy = y - other.y;
|
||||||
|
// return dx * dx + dy * dy;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// T distance(const Vec2D &other) const
|
||||||
|
// requires std::floating_point<T>
|
||||||
|
// {
|
||||||
|
// return sqrt(distance_squared(other));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// void normalize()
|
||||||
|
// requires std::floating_point<T>
|
||||||
|
// {
|
||||||
|
// auto length = sqrt(x * x + y * y);
|
||||||
|
// if (length < EQUALITY_LIMIT) {
|
||||||
|
// x = y = 0;
|
||||||
|
// } else {
|
||||||
|
// x /= length;
|
||||||
|
// y /= length;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Vec2D normalized()
|
||||||
|
// requires std::floating_point<T>
|
||||||
|
// {
|
||||||
|
// Vec2D v(*this);
|
||||||
|
// v.normalize();
|
||||||
|
// return v;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Vec2D orthogonal() const
|
||||||
|
// {
|
||||||
|
// Vec2D v(*this);
|
||||||
|
//
|
||||||
|
// std::swap(v.x, v.y);
|
||||||
|
// v.x = -v.x;
|
||||||
|
// return v;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// template <typename U> Vec2D(std::initializer_list<U> list) {
|
||||||
|
// assert(list.size() == 2);
|
||||||
|
// auto first_element = *list.begin();
|
||||||
|
// auto second_element = *(list.begin() + 1);
|
||||||
|
// x = static_cast<T>(first_element);
|
||||||
|
// y = static_cast<T>(second_element);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// T x, y;
|
||||||
|
//
|
||||||
|
// friend std::ostream &operator<<(std::ostream &os, const Vec2D &obj) {
|
||||||
|
// os << "( " << obj.x << ", " << obj.y << ")";
|
||||||
|
// return os;
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
Loading…
x
Reference in New Issue
Block a user