/** \file G3D/Vector2.h 2D vector class \maintainer Morgan McGuire, http://graphics.cs.williams.edu \created 2001-06-02 \edited 2011-11-30 Copyright 2000-2012, Morgan McGuire. All rights reserved. */ #ifndef G3D_Vector2_h #define G3D_Vector2_h #include #include "G3D/platform.h" #include "G3D/g3dmath.h" #include "G3D/Table.h" #include "G3D/HashTrait.h" #include "G3D/Vector2int16.h" #include "G3D/Vector2unorm16.h" #include "G3D/Random.h" namespace G3D { class Vector2; class Vector3; class Vector4; class Vector2int32; class Any; /** Do not subclass-- this implementation makes assumptions about the memory layout. */ class Vector2 { private: // Hidden operators bool operator<(const Vector2&) const; bool operator>(const Vector2&) const; bool operator<=(const Vector2&) const; bool operator>=(const Vector2&) const; public: float x; float y; /** \param any Must either Vector2(#, #) or Vector2 {x = #, y = #}*/ Vector2(const Any& any); /** Converts the Vector2 to an Any. */ Any toAny() const; /** Creates the zero vector */ Vector2(); Vector2(class TextInput& t); Vector2(class BinaryInput& b); Vector2(float x, float y); Vector2(float coordinate[2]); Vector2(double coordinate[2]); Vector2(const Vector2& other); Vector2(const Vector2int16& other); Vector2(const Vector2unorm16& other); // explicit because of precision loss explicit Vector2(const Vector2int32& other); Vector2& operator=(const Any& a); void serialize(class BinaryOutput& b) const; void deserialize(class BinaryInput& b); void serialize(class TextOutput& t) const; void deserialize(class TextInput& t); float& operator[](int i); const float& operator[](int i) const; // assignment and comparison Vector2& operator=(const Vector2& other); bool operator==(const Vector2& other) const; bool operator!=(const Vector2& other) const; size_t hashCode() const; bool fuzzyEq(const Vector2& other) const; bool fuzzyNe(const Vector2& other) const; /** Returns true if this vector has finite length */ bool isFinite() const; /** True if any field is NaN */ bool isNaN() const { return G3D::isNaN(x) || G3D::isNaN(y); } /** Returns true if this vector has length == 0 */ bool isZero() const; /** Returns true if this vector has length == 1 */ bool isUnit() const; // arithmetic operations Vector2 operator+(const Vector2& v) const; Vector2 operator-(const Vector2& v) const; Vector2 operator*(float s) const; /** Raise each component of this vector to a power */ Vector2 pow(float p) const { return Vector2(powf(x, p), powf(y, p)); } /** Array (pointwise) multiplication */ Vector2 operator*(const Vector2& v) const; /** Array division */ Vector2 operator/(const Vector2& v) const; Vector2 operator/(float s) const; /** Unary minus */ Vector2 operator-() const; /** x + y */ inline float sum() const { return x + y; } /** Linear interpolation */ inline Vector2 lerp(const Vector2& v, float alpha) const { return (*this) + (v - *this) * alpha; } inline Vector2 clamp(const Vector2& low, const Vector2& high) const { return Vector2( G3D::clamp(x, low.x, high.x), G3D::clamp(y, low.y, high.y)); } inline Vector2 clamp(float low, float high) const { return Vector2( (float)G3D::clamp(x, low, high), (float)G3D::clamp(y, low, high)); } // arithmetic updates Vector2& operator+=(const Vector2&); Vector2& operator-=(const Vector2&); Vector2& operator*=(float); Vector2& operator/=(float); Vector2& operator*=(const Vector2&); Vector2& operator/=(const Vector2&); // vector operations /** Magnitude of the vector */ float length() const; /** Returns a unit-length version of this vector. Returns nan if length is almost zero. */ Vector2 direction() const; /** Returns Vector2::zero() is magnitude is almost zero, otherwise returns unit-length vector. */ Vector2 directionOrZero() const; /** Potentially less accurate but faster than direction(). Only works if System::hasSSE is true. */ Vector2 fastDirection() const { return direction(); } float squaredLength() const; float dot(const Vector2& s) const; /** Componentwise absolute value */ Vector2 abs() const { return Vector2(fabs(x), fabs(y)); } /** Component-wise minimum */ Vector2 min(const Vector2& v) const; /** Component-wise maximum */ Vector2 max(const Vector2& v) const; /** Component-wise argmax(abs(), v.abs()). For the larger magnitude vector, simply use (a.squaredMagnitude() > b.squaredMagnitude) ? a : b. \sa max */ Vector2 maxAbs(const Vector2& v) const { return Vector2(::fabsf(x) > ::fabsf(v.x) ? x : v.x, ::fabsf(y) > ::fabsf(v.y) ? y : v.y); } /** Component-wise argmin(abs(), v.abs()). For the smaller magnitude vector, simply use (a.squaredMagnitude() < b.squaredMagnitude) ? a : b. \sa max */ Vector2 minAbs(const Vector2& v) const { return Vector2(::fabsf(x) < ::fabsf(v.x) ? x : v.x, ::fabsf(y) < ::fabsf(v.y) ? y : v.y); } /** Uniformly distributed random vector on the unit sphere */ static Vector2 random(Random& r = Random::common()); // Special values. // Intentionally not inlined: see Matrix3::identity() for details. static const Vector2& zero(); static const Vector2& one(); static const Vector2& unitX(); static const Vector2& unitY(); static const Vector2& inf(); static const Vector2& nan(); /** smallest (most negative) representable vector */ static const Vector2& minFinite(); /** Largest representable vector */ static const Vector2& maxFinite(); std::string toString() const; // 2-char swizzles Vector2 xx() const; Vector2 yx() const; Vector2 xy() const; Vector2 yy() const; // 3-char swizzles Vector3 xxx() const; Vector3 yxx() const; Vector3 xyx() const; Vector3 yyx() const; Vector3 xxy() const; Vector3 yxy() const; Vector3 xyy() const; Vector3 yyy() const; // 4-char swizzles Vector4 xxxx() const; Vector4 yxxx() const; Vector4 xyxx() const; Vector4 yyxx() const; Vector4 xxyx() const; Vector4 yxyx() const; Vector4 xyyx() const; Vector4 yyyx() const; Vector4 xxxy() const; Vector4 yxxy() const; Vector4 xyxy() const; Vector4 yyxy() const; Vector4 xxyy() const; Vector4 yxyy() const; Vector4 xyyy() const; Vector4 yyyy() const; }; inline Vector2 operator*(double s, const Vector2& v) { return v * (float)s; } inline Vector2 operator*(float s, const Vector2& v) { return v * s; } inline Vector2 operator*(int s, const Vector2& v) { return v * (float)s; } inline Vector2::Vector2 () : x(0.0f), y(0.0f) { } inline Vector2::Vector2(float _x, float _y) : x(_x), y(_y) { } inline Vector2::Vector2 (float afCoordinate[2]) { x = afCoordinate[0]; y = afCoordinate[1]; } inline Vector2::Vector2 (double afCoordinate[2]) { x = (float)afCoordinate[0]; y = (float)afCoordinate[1]; } inline Vector2::Vector2 (const Vector2& rkVector) { x = rkVector.x; y = rkVector.y; } inline Vector2::Vector2 (const Vector2int16& v) : x(v.x), y(v.y) { } inline Vector2::Vector2 (const Vector2unorm16& v) : x(float(v.x)), y(float(v.y)) { } inline float& Vector2::operator[] (int i) { return ((float*)this)[i]; } inline const float& Vector2::operator[] (int i) const { return ((float*)this)[i]; } inline Vector2& Vector2::operator= (const Vector2& rkVector) { x = rkVector.x; y = rkVector.y; return *this; } inline bool Vector2::operator== (const Vector2& rkVector) const { return ( x == rkVector.x && y == rkVector.y); } inline bool Vector2::operator!= (const Vector2& rkVector) const { return ( x != rkVector.x || y != rkVector.y); } inline Vector2 Vector2::operator+ (const Vector2& rkVector) const { return Vector2(x + rkVector.x, y + rkVector.y); } inline Vector2 Vector2::operator- (const Vector2& rkVector) const { return Vector2(x - rkVector.x, y - rkVector.y); } inline Vector2 Vector2::operator* (float fScalar) const { return Vector2(fScalar*x, fScalar*y); } inline Vector2 Vector2::operator- () const { return Vector2( -x, -y); } inline Vector2& Vector2::operator+= (const Vector2& rkVector) { x += rkVector.x; y += rkVector.y; return *this; } inline Vector2& Vector2::operator-= (const Vector2& rkVector) { x -= rkVector.x; y -= rkVector.y; return *this; } inline Vector2& Vector2::operator*= (float fScalar) { x *= fScalar; y *= fScalar; return *this; } inline Vector2& Vector2::operator*= (const Vector2& rkVector) { x *= rkVector.x; y *= rkVector.y; return *this; } inline Vector2& Vector2::operator/= (const Vector2& rkVector) { x /= rkVector.x; y /= rkVector.y; return *this; } inline Vector2 Vector2::operator* (const Vector2& rkVector) const { return Vector2(x * rkVector.x, y * rkVector.y); } inline Vector2 Vector2::operator/ (const Vector2& rkVector) const { return Vector2(x / rkVector.x, y / rkVector.y); } inline float Vector2::squaredLength () const { return x*x + y*y; } inline float Vector2::length () const { return sqrtf(x*x + y*y); } inline Vector2 Vector2::direction () const { float lenSquared = x * x + y * y; if (lenSquared != 1.0f) { return *this / sqrtf(lenSquared); } else { return *this; } } inline Vector2 Vector2::directionOrZero() const { float mag = length(); if (mag < 0.0000001f) { return Vector2::zero(); } else if (mag < 1.00001f && mag > 0.99999f) { return *this; } else { return *this * (1.0f / mag); } } inline float Vector2::dot (const Vector2& rkVector) const { return x*rkVector.x + y*rkVector.y; } inline Vector2 Vector2::min(const Vector2 &v) const { return Vector2(G3D::min(v.x, x), G3D::min(v.y, y)); } inline Vector2 Vector2::max(const Vector2 &v) const { return Vector2(G3D::max(v.x, x), G3D::max(v.y, y)); } inline bool Vector2::fuzzyEq(const Vector2& other) const { return G3D::fuzzyEq((*this - other).squaredLength(), 0); } inline bool Vector2::fuzzyNe(const Vector2& other) const { return G3D::fuzzyNe((*this - other).squaredLength(), 0); } inline bool Vector2::isFinite() const { return G3D::isFinite(x) && G3D::isFinite(y); } inline bool Vector2::isZero() const { return G3D::fuzzyEq(fabsf(x) + fabsf(y), 0.0f); } inline bool Vector2::isUnit() const { return G3D::fuzzyEq(squaredLength(), 1.0f); } typedef Vector2 Point2; void serialize(const Vector2& v, class BinaryOutput& b); void deserialize(Vector2& v, class BinaryInput& b); } // namespace G3D template <> struct HashTrait { static size_t hashCode(const G3D::Vector2& key) { return key.hashCode(); } }; // Intentionally outside namespace to avoid operator overloading confusion inline G3D::Vector2 operator*(double s, const G3D::Vector2& v) { return v * (float)s; } inline G3D::Vector2 operator*(int s, const G3D::Vector2& v) { return v * (float)s; } #endif