#pragma once #include namespace Scop { template constexpr Vec3::Vec3(T X, T Y, T Z) : x(X), y(Y), z(Z) {} template constexpr Vec3::Vec3(T X, const Vec2& vec) : x(X), y(vec.x), z(vec.y) {} template constexpr Vec3::Vec3(T scale) : x(scale), y(scale), z(scale) {} template constexpr Vec3::Vec3(const Vec2& vec, T Z) : x(vec.x), y(vec.y), z(Z) {} template template constexpr Vec3::Vec3(const Vec3& vec) : x(static_cast(vec.x)), y(static_cast(vec.y)), z(static_cast(vec.z)) {} template constexpr Vec3::Vec3(const Vec4& vec) : x(vec.x), y(vec.y), z(vec.z) {} template T Vec3::AbsDotProduct(const Vec3& vec) const { return std::abs(x * vec.x) + std::abs(y * vec.y) + std::abs(z * vec.z); } template constexpr bool Vec3::ApproxEqual(const Vec3& vec, T maxDifference) const { return NumberEquals(x, vec.x, maxDifference) && NumberEquals(y, vec.y, maxDifference) && NumberEquals(z, vec.z, maxDifference); } template constexpr Vec3 Vec3::CrossProduct(const Vec3& vec) const { return Vec3(y * vec.z - z * vec.y, z * vec.x - x * vec.z, x * vec.y - y * vec.x); } template template U Vec3::Distance(const Vec3& vec) const { return static_cast(std::sqrt(static_cast(SquaredDistance(vec)))); } template constexpr T Vec3::DotProduct(const Vec3& vec) const { return x * vec.x + y * vec.y + z * vec.z; } template Vec3 Vec3::GetAbs() const { return Vec3(std::abs(x), std::abs(y), std::abs(z)); } template template U Vec3::GetLength() const { return static_cast(std::sqrt(static_cast(GetSquaredLength()))); } template Vec3 Vec3::GetNormal(T* length) const { Vec3 vec(*this); vec.Normalize(length); return vec; } template constexpr T Vec3::GetSquaredLength() const { return x*x + y*y + z*z; } template constexpr Vec3& Vec3::Maximize(const Vec3& vec) { if (vec.x > x) x = vec.x; if (vec.y > y) y = vec.y; if (vec.z > z) z = vec.z; return *this; } template constexpr Vec3& Vec3::Minimize(const Vec3& vec) { if (vec.x < x) x = vec.x; if (vec.y < y) y = vec.y; if (vec.z < z) z = vec.z; return *this; } template Vec3& Vec3::Normalize(T* length) { T norm = GetLength(); if (norm > T(0.0)) { T invNorm = T(1.0) / norm; x *= invNorm; y *= invNorm; z *= invNorm; } if (length) *length = norm; return *this; } template constexpr T Vec3::SquaredDistance(const Vec3& vec) const { return (*this - vec).GetSquaredLength(); } template std::string Vec3::ToString() const { return "Vec3(" + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(z) + ')'; } template constexpr T& Vec3::operator[](std::size_t i) { Scop::Assert(i < 3, "index out of range"); return *(&x + i); } template constexpr const T& Vec3::operator[](std::size_t i) const { Scop::Assert(i < 3, "index out of range"); return *(&x + i); } template constexpr const Vec3& Vec3::operator+() const { return *this; } template constexpr Vec3 Vec3::operator-() const { return Vec3(-x, -y, -z); } template constexpr Vec3 Vec3::operator+(const Vec3& vec) const { return Vec3(x + vec.x, y + vec.y, z + vec.z); } template constexpr Vec3 Vec3::operator-(const Vec3& vec) const { return Vec3(x - vec.x, y - vec.y, z - vec.z); } template constexpr Vec3 Vec3::operator*(const Vec3& vec) const { return Vec3(x * vec.x, y * vec.y, z * vec.z); } template constexpr Vec3 Vec3::operator*(T scale) const { return Vec3(x * scale, y * scale, z * scale); } template constexpr Vec3 Vec3::operator/(const Vec3& vec) const { return Vec3(x / vec.x, y / vec.y, z / vec.z); } template constexpr Vec3 Vec3::operator/(T scale) const { return Vec3(x / scale, y / scale, z / scale); } template constexpr Vec3 Vec3::operator%(const Vec3& vec) const { return Vec3(Mod(x, vec.x), Mod(y, vec.y), Mod(z, vec.z)); } template constexpr Vec3 Vec3::operator%(T mod) const { return Vec3(Mod(x, mod), Mod(y, mod), Mod(z, mod)); } template constexpr Vec3& Vec3::operator+=(const Vec3& vec) { x += vec.x; y += vec.y; z += vec.z; return *this; } template constexpr Vec3& Vec3::operator-=(const Vec3& vec) { x -= vec.x; y -= vec.y; z -= vec.z; return *this; } template constexpr Vec3& Vec3::operator*=(const Vec3& vec) { x *= vec.x; y *= vec.y; z *= vec.z; return *this; } template constexpr Vec3& Vec3::operator*=(T scale) { x *= scale; y *= scale; z *= scale; return *this; } template constexpr Vec3& Vec3::operator/=(const Vec3& vec) { x /= vec.x; y /= vec.y; z /= vec.z; return *this; } template constexpr Vec3& Vec3::operator/=(T scale) { x /= scale; y /= scale; z /= scale; return *this; } template constexpr Vec3& Vec3::operator%=(const Vec3& vec) { x = Mod(x, vec.x); y = Mod(y, vec.y); z = Mod(z, vec.z); return *this; } template constexpr Vec3& Vec3::operator%=(T mod) { x = Mod(x, mod); y = Mod(y, mod); z = Mod(z, mod); return *this; } template constexpr bool Vec3::operator==(const Vec3& vec) const { return x == vec.x && y == vec.y && z == vec.z; } template constexpr bool Vec3::operator!=(const Vec3& vec) const { return !operator==(vec); } template constexpr bool Vec3::operator<(const Vec3& vec) const { if (x != vec.x) return x < vec.x; if (y != vec.y) return y < vec.y; return z < vec.z; } template constexpr bool Vec3::operator<=(const Vec3& vec) const { if (x != vec.x) return x < vec.x; if (y != vec.y) return y < vec.y; return z <= vec.z; } template constexpr bool Vec3::operator>(const Vec3& vec) const { if (x != vec.x) return x > vec.x; if (y != vec.y) return y > vec.y; return z > vec.z; } template constexpr bool Vec3::operator>=(const Vec3& vec) const { if (x != vec.x) return x > vec.x; if (y != vec.y) return y > vec.y; return z >= vec.z; } template constexpr Vec3 Vec3::Apply(T(*func)(T), const Vec3& vec) { return Vec3(func(vec.x), func(vec.y), func(vec.z)); } template constexpr bool Vec3::ApproxEqual(const Vec3& lhs, const Vec3& rhs, T maxDifference) { return lhs.ApproxEqual(rhs, maxDifference); } template constexpr Vec3 Vec3::CrossProduct(const Vec3& vec1, const Vec3& vec2) { return vec1.CrossProduct(vec2); } template constexpr T Vec3::DotProduct(const Vec3& vec1, const Vec3& vec2) { return vec1.DotProduct(vec2); } template constexpr Vec3 Vec3::Backward() { return Vec3(0, 0, 1); } template template U Vec3::Distance(const Vec3& vec1, const Vec3& vec2) { return vec1.Distance(vec2); } template constexpr Vec3 Vec3::Down() { return Vec3(0, -1, 0); } template constexpr Vec3 Vec3::Forward() { return Vec3(0, 0, -1); } template constexpr Vec3 Vec3::Left() { return Vec3(-1, 0, 0); } template constexpr Vec3 Vec3::Max(const Vec3& lhs, const Vec3& rhs) { Vec3 max = lhs; max.Maximize(rhs); return max; } template constexpr Vec3 Vec3::Min(const Vec3& lhs, const Vec3& rhs) { Vec3 min = lhs; min.Minimize(rhs); return min; } template Vec3 Vec3::Normalize(const Vec3& vec) { return vec.GetNormal(); } template constexpr Vec3 Vec3::Right() { return Vec3(1, 0, 0); } template constexpr T Vec3::SquaredDistance(const Vec3& vec1, const Vec3& vec2) { return vec1.SquaredDistance(vec2); } template constexpr Vec3 Vec3::Unit() { return Vec3(1); } template constexpr Vec3 Vec3::UnitX() { return Vec3(1, 0, 0); } template constexpr Vec3 Vec3::UnitY() { return Vec3(0, 1, 0); } template constexpr Vec3 Vec3::UnitZ() { return Vec3(0, 0, 1); } template constexpr Vec3 Vec3::Up() { return Vec3(0, 1, 0); } template constexpr Vec3 Vec3::Zero() { return Vec3(0, 0, 0); } template std::ostream& operator<<(std::ostream& out, const Vec3& vec) { return out << "Vec3(" << vec.x << ", " << vec.y << ", " << vec.z << ')'; } template constexpr Vec3 operator*(T scale, const Vec3& vec) { return Vec3(scale * vec.x, scale * vec.y, scale * vec.z); } template constexpr Vec3 operator/(T scale, const Vec3& vec) { return Vec3(scale / vec.x, scale / vec.y, scale / vec.z); } template constexpr Vec3 operator%(T mod, const Vec3& vec) { return Vec3(Mod(mod, vec.x), Mod(mod, vec.y), Mod(mod, vec.z)); } }