You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Legacy/CryCommon/Cry_Vector2.h

385 lines
11 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
// Description : Common matrix class
#ifndef CRYINCLUDE_CRYCOMMON_CRY_VECTOR2_H
#define CRYINCLUDE_CRYCOMMON_CRY_VECTOR2_H
#pragma once
#include <AzCore/RTTI/TypeInfo.h>
#include "Cry_Math.h"
template<class F>
struct Vec2_tpl
{
typedef F value_type;
enum
{
component_count = 2
};
F x, y;
#ifdef _DEBUG
ILINE Vec2_tpl()
{
if constexpr (sizeof(F) == 4)
{
uint32* p = alias_cast<uint32*>(&x);
p[0] = F32NAN;
p[1] = F32NAN;
}
if constexpr (sizeof(F) == 8)
{
uint64* p = alias_cast<uint64*>(&x);
p[0] = F64NAN;
p[1] = F64NAN;
}
}
#else
ILINE Vec2_tpl() {}
#endif
ILINE Vec2_tpl(type_zero)
: x(0)
, y(0) {}
ILINE Vec2_tpl(F vx, F vy) { x = vx; y = vy; }
explicit ILINE Vec2_tpl(F m) { x = y = m; }
ILINE Vec2_tpl& set(F nx, F ny) { x = F(nx); y = F(ny); return *this; }
template<class F1>
ILINE Vec2_tpl(const Vec2_tpl<F1>& src) { x = F(src.x); y = F(src.y); }
template<class F1>
ILINE explicit Vec2_tpl(const Vec3_tpl<F1>& src) { x = F(src.x); y = F(src.y); }
template<class F1>
ILINE explicit Vec2_tpl(const F1* psrc) { x = F(psrc[0]); y = F(psrc[1]); }
explicit ILINE Vec2_tpl(const Vec3_tpl<F>& v)
: x((F)v.x)
, y((F)v.y) { assert(this->IsValid()); }
ILINE Vec2_tpl& operator=(const Vec2_tpl& src) { x = src.x; y = src.y; return *this; }
//template<class F1> Vec2_tpl& operator=(const Vec2_tpl<F1>& src) { x=F(src.x); y=F(src.y); return *this; }
//template<class F1> Vec2_tpl& operator=(const Vec3_tpl<F1>& src) { x=F(src.x); y=F(src.y); return *this; }
ILINE int operator!() const { return x == 0 && y == 0; }
// The default Normalize function is in fact "safe". 0 vectors remain unchanged.
Vec2_tpl& Normalize()
{
F fInvLen = isqrt_safe_tpl(x * x + y * y);
x *= fInvLen;
y *= fInvLen;
return *this;
}
// Normalize if non-0, otherwise set to specified "safe" value.
Vec2_tpl& NormalizeSafe(const struct Vec2_tpl<F>& safe = Vec2_tpl<F>(0, 0))
{
F fLen2 = x * x + y * y;
if (fLen2 > 0.0f)
{
F fInvLen = isqrt_tpl(fLen2);
x *= fInvLen;
y *= fInvLen;
}
else
{
*this = safe;
}
return *this;
}
Vec2_tpl GetNormalized() const
{
F fInvLen = isqrt_safe_tpl(x * x + y * y);
return *this * fInvLen;
}
Vec2_tpl GetNormalizedSafe(const struct Vec2_tpl<F>& safe = Vec2_tpl<F>(1, 0)) const
{
F fLen2 = x * x + y * y;
if (fLen2 > 0.0f)
{
F fInvLen = isqrt_tpl(fLen2);
return *this * fInvLen;
}
else
{
return safe;
}
}
ILINE bool IsEquivalent(const Vec2_tpl<F>& v1, F epsilon = VEC_EPSILON) const
{
assert(v1.IsValid());
assert(this->IsValid());
return ((fabs_tpl(x - v1.x) <= epsilon) && (fabs_tpl(y - v1.y) <= epsilon));
}
ILINE static bool IsEquivalent(const Vec2_tpl<F>& v0, const Vec2_tpl<F>& v1, F epsilon = VEC_EPSILON)
{
assert(v0.IsValid());
assert(v1.IsValid());
return ((fabs_tpl(v0.x - v1.x) <= epsilon) && (fabs_tpl(v0.y - v1.y) <= epsilon));
}
ILINE F GetLength() const
{
return sqrt_tpl(x * x + y * y);
}
ILINE F GetLengthSquared() const
{
return x * x + y * y;
}
ILINE F GetLength2() const
{
return x * x + y * y;
}
void SetLength(F fLen)
{
F fLenMe = GetLength2();
if (fLenMe < 0.00001f * 0.00001f)
{
return;
}
fLenMe = fLen * isqrt_tpl(fLenMe);
x *= fLenMe;
y *= fLenMe;
}
ILINE F area() const { return x * y; }
ILINE F& operator[](int idx) { return *((F*)&x + idx); }
ILINE F operator[](int idx) const { return *((F*)&x + idx); }
ILINE operator F*() { return &x; }
ILINE Vec2_tpl& flip() { x = -x; y = -y; return *this; }
ILINE Vec2_tpl& zero() { x = y = 0; return *this; }
ILINE Vec2_tpl rot90ccw() const { return Vec2_tpl(-y, x); }
ILINE Vec2_tpl rot90cw() const { return Vec2_tpl(y, -x); }
#ifdef quotient_h
quotient_tpl<F> fake_atan2() const
{
quotient_tpl<F> res;
int quad = -(signnz(x * x - y * y) - 1 >> 1); // hope the optimizer will remove complement shifts and adds
if (quad)
{
res.x = -y;
res.y = x;
}
else
{
res.x = x;
res.y = y;
}
int sgny = signnz(res.y);
quad |= 1 - sgny; //(res.y<0)<<1;
res.x *= sgny;
res.y *= sgny;
res += 1 + (quad << 1);
return res;
}
#endif
ILINE F atan2() const { return atan2_tpl(y, x); }
ILINE Vec2_tpl operator-() const { return Vec2_tpl(-x, -y); }
ILINE Vec2_tpl operator*(F k) const { return Vec2_tpl(x * k, y * k); }
ILINE Vec2_tpl& operator*=(F k) { x *= k; y *= k; return *this; }
ILINE Vec2_tpl operator/(F k) const { return *this * ((F)1.0 / k); }
ILINE Vec2_tpl& operator/=(F k) { return *this *= ((F)1.0 / k); }
// bool operator==(const Vec2_tpl<F> &vec) { return x == vec.x && y == vec.y; }
ILINE bool operator!=(const Vec2_tpl<F>& vec) { return !(*this == vec); }
ILINE friend bool operator==(const Vec2_tpl<F>& left, const Vec2_tpl<F>& right) { return left.x == right.x && left.y == right.y; }
ILINE friend bool operator!=(const Vec2_tpl<F>& left, const Vec2_tpl<F>& right) { return !(left == right); }
ILINE bool IsZero(F e = (F)0.0) const
{
return (fabs_tpl(x) <= e) && (fabs_tpl(y) <= e);
}
// IsZeroSlow would be a better name [5/20/2010 evgeny]
ILINE bool IsZeroFast(F e = (F)0.0003) const
{
return (fabs_tpl(x) + fabs_tpl(y)) <= e;
}
ILINE F Dot(const Vec2_tpl& rhs) const {return x * rhs.x + y * rhs.y; }
/// returns a vector perpendicular to this one (this->Cross(newVec) points "up")
ILINE Vec2_tpl Perp() const {return Vec2_tpl(-y, x); }
// The size of the "paralell-trapets" area spanned by the two vectors.
ILINE F Cross (const Vec2_tpl<F>& v) const
{
return float (x * v.y - y * v.x);
}
/*!
* Linear-Interpolation between Vec3 (lerp)
*
* Example:
* Vec3 r=Vec3::CreateLerp( p, q, 0.345f );
*/
ILINE void SetLerp(const Vec2_tpl<F>& p, const Vec2_tpl<F>& q, F t) { *this = p * (1.0f - t) + q * t; }
ILINE static Vec2_tpl<F> CreateLerp(const Vec2_tpl<F>& p, const Vec2_tpl<F>& q, F t) { return p * (1.0f - t) + q * t; }
/*!
* Spherical-Interpolation between 3d-vectors (geometrical slerp)
* both vectors are assumed to be normalized.
*
* Example:
* Vec3 r=Vec3::CreateSlerp( p, q, 0.5674f );
*/
void SetSlerp(const Vec2_tpl<F>& p, const Vec2_tpl<F>& q, F t)
{
assert((fabs_tpl(1 - (p | p))) < 0.005); //check if unit-vector
assert((fabs_tpl(1 - (q | q))) < 0.005); //check if unit-vector
// calculate cosine using the "inner product" between two vectors: p*q=cos(radiant)
F cosine = (p | q);
//we explore the special cases where the both vectors are very close together,
//in which case we approximate using the more economical LERP and avoid "divisions by zero" since sin(Angle) = 0 as Angle=0
if (cosine >= (F)0.99)
{
SetLerp(p, q, t); //perform LERP:
this->Normalize();
}
else
{
//perform SLERP: because of the LERP-check above, a "division by zero" is not possible
F rad = acos_tpl(cosine);
F scale_0 = sin_tpl((1 - t) * rad);
F scale_1 = sin_tpl(t * rad);
*this = (p * scale_0 + q * scale_1) / sin_tpl(rad);
this->Normalize();
}
}
ILINE static Vec2_tpl<F> CreateSlerp(const Vec2_tpl<F>& p, const Vec2_tpl<F>& q, F t)
{
Vec2_tpl<F> v;
v.SetSlerp(p, q, t);
return v;
}
bool IsValid() const
{
if (!NumberValid(x))
{
return false;
}
if (!NumberValid(y))
{
return false;
}
return true;
}
ILINE F GetDistance(const Vec2_tpl<F>& vec1) const
{
return sqrt_tpl((x - vec1.x) * (x - vec1.x) + (y - vec1.y) * (y - vec1.y));
}
AUTO_STRUCT_INFO
};
///////////////////////////////////////////////////////////////////////////////
// Typedefs //
///////////////////////////////////////////////////////////////////////////////
typedef Vec2_tpl<f32> Vec2; // always 32 bit
typedef Vec2_tpl<f64> Vec2d; // always 64 bit
typedef Vec2_tpl<int32> Vec2i;
typedef Vec2_tpl<uint32> Vec2ui;
typedef Vec2_tpl<real> Vec2r; // variable float precision. depending on the target system it can be 32, 64 or 80 bit
typedef Vec2_tpl<float> vector2f;
#if defined(LINUX64)
typedef Vec2_tpl<int> vector2l;
#else
typedef Vec2_tpl<long> vector2l;
#endif
typedef Vec2_tpl<float> vector2df;
typedef Vec2_tpl<real> vector2d;
typedef Vec2_tpl<int> vector2di;
typedef Vec2_tpl<unsigned int> vector2dui;
template<class F>
Vec2_tpl<F> operator*(F op1, const Vec2_tpl<F>& op2) {return Vec2_tpl<F>(op1 * op2.x, op1 * op2.y); }
template<class F1, class F2>
F1 operator*(const Vec2_tpl<F1>& op1, const Vec2_tpl<F2>& op2) { return op1.x * op2.x + op1.y * op2.y; } // dot product
template<class F1, class F2>
F1 operator|(const Vec2_tpl<F1>& op1, const Vec2_tpl<F2>& op2) { return op1.x * op2.x + op1.y * op2.y; } // dot product
template<class F1, class F2>
F1 operator^(const Vec2_tpl<F1>& op1, const Vec2_tpl<F2>& op2) { return op1.x * op2.y - op1.y * op2.x; } // cross product
template<class F1, class F2>
Vec2_tpl<F1> operator+(const Vec2_tpl<F1>& op1, const Vec2_tpl<F2>& op2)
{
return Vec2_tpl<F1>(op1.x + op2.x, op1.y + op2.y);
}
template<class F1, class F2>
Vec2_tpl<F1> operator-(const Vec2_tpl<F1>& op1, const Vec2_tpl<F2>& op2)
{
return Vec2_tpl<F1>(op1.x - op2.x, op1.y - op2.y);
}
template<class F1, class F2>
Vec2_tpl<F1>& operator+=(Vec2_tpl<F1>& op1, const Vec2_tpl<F2>& op2)
{
op1.x += op2.x;
op1.y += op2.y;
return op1;
}
template<class F1, class F2>
Vec2_tpl<F1>& operator-=(Vec2_tpl<F1>& op1, const Vec2_tpl<F2>& op2)
{
op1.x -= op2.x;
op1.y -= op2.y;
return op1;
}
template<class F>
bool operator==(const Vec2_tpl<F>& left, const Vec2_tpl<F>& right)
{
return left.x == right.x && left.y == right.y;
}
template<>
ILINE Vec2 clamp_tpl<Vec2>(Vec2 X, Vec2 Min, Vec2 Max)
{
return Vec2(clamp_tpl(X.x, Min.x, Max.x), clamp_tpl(X.y, Min.y, Max.y));
}
// declare common constants. Must be done after the class for compiler conformance
// (msvc and clang handle instantiation differently)
const Vec2_tpl<float> Vec2_Zero(0, 0);
const Vec2_tpl<float> Vec2_OneX(1, 0);
const Vec2_tpl<float> Vec2_OneY(0, 1);
const Vec2_tpl<float> Vec2_One(1, 1);
namespace AZ
{
AZ_TYPE_INFO_SPECIALIZE(Vec2, "{844131BA-9565-42F3-8482-6F65A6D5FC59}");
}
#endif // CRYINCLUDE_CRYCOMMON_CRY_VECTOR2_H