diff --git a/doomsday/libdeng2/include/de/vector.h b/doomsday/libdeng2/include/de/vector.h index 534559d050..1d19d75b57 100644 --- a/doomsday/libdeng2/include/de/vector.h +++ b/doomsday/libdeng2/include/de/vector.h @@ -66,8 +66,12 @@ class Vector2 return Vector2(ddouble(x), ddouble(y)); } Type &operator [] (int index) { - if(index == 0) return x; - if(index == 1) return y; + DENG2_ASSERT(index >= 0 && index <= 1); + Type *ptrs[] = { &x, &y }; + if(index >= 0 && index < 2) + { + return *ptrs[index]; + } throw Error("Vector2::operator []", QString("Illegal index %1").arg(index)); } Type const &operator [] (int index) const { @@ -98,6 +102,14 @@ class Vector2 y -= other.y; return *this; } + inline Vector2 &operator *= (ddouble scalar) { + x *= scalar; + y *= scalar; + return *this; + } + inline Vector2 &operator /= (ddouble scalar) { + return (*this) *= 1.0 / scalar; + } bool operator > (Vector2 const &other) const { return x > other.x && y > other.y; } @@ -113,6 +125,13 @@ class Vector2 ddouble length() const { return std::sqrt(ddouble(x*x + y*y)); } + Vector2 normalize() const { + ddouble len = length(); + if(len != 0) { + return *this / len; + } + return Vector2(); + } String asText() const { String str; QTextStream s(&str); @@ -192,7 +211,7 @@ class Vector3 : public Vector2 { public: Vector3(Type a = 0, Type b = 0, Type c = 0) : Vector2(a, b), z(c) {} - Vector3(Vector2 const &v2) : Vector2(v2), z(0) {} + Vector3(Vector2 const &v2, Type c = 0) : Vector2(v2), z(c) {} Vector3(Type const *abc) : Vector2(abc), z(abc[2]) {} /// Conversion operator to a float vector. @@ -204,9 +223,15 @@ class Vector3 : public Vector2 return Vector3(Vector2::x, Vector2::y, z); } Type &operator [] (int index) { - if(index < 2) return Vector2::operator [] (index); - if(index == 2) return z; - throw Error("Vector3::operator[]", QString("Illegal index %1").arg(index)); + DENG2_ASSERT(index >= 0 && index <= 2); + Type *ptrs[] = { &(this->Vector2::x), + &(this->Vector2::y), + &z }; + if(index >= 0 && index < 3) + { + return *ptrs[index]; + } + throw Error("Vector3::operator []", QString("Illegal index %1").arg(index)); } Type const &operator [] (int index) const { return const_cast &>(*this)[index]; @@ -224,6 +249,9 @@ class Vector3 : public Vector2 return Vector3(Type(Vector2::x * scalar), Type(Vector2::y * scalar), Type(z * scalar)); } + Vector3 operator / (ddouble scalar) const { + return *this * (1.0 / scalar); + } Vector3 operator * (Vector3 const &other) const { return Vector3(Vector2::x * other.x, Vector2::y * other.y, z * other.z); } @@ -239,6 +267,14 @@ class Vector3 : public Vector2 z -= other.z; return *this; } + inline Vector3 &operator *= (ddouble scalar) { + Vector2::operator *= (scalar); + z *= scalar; + return *this; + } + inline Vector3 &operator /= (ddouble scalar) { + return (*this) *= 1.0 / scalar; + } bool operator > (Vector3 const &other) const { return Vector2::operator > (other) && z > other.z; } @@ -251,8 +287,16 @@ class Vector3 : public Vector2 bool operator <= (Vector3 const &other) const { return Vector2::operator <= (other) && z <= other.z; } - ddouble length() const { return std::sqrt(Vector2::x*Vector2::x + - Vector2::y*Vector2::y + z*z); } + ddouble length() const { + return std::sqrt(Vector2::x*Vector2::x + Vector2::y*Vector2::y + z*z); + } + Vector3 normalize() const { + ddouble const len = length(); + if(len != 0) { + return *this / len; + } + return Vector3(); + } String asText() const { String str; QTextStream os(&str); @@ -265,6 +309,11 @@ class Vector3 : public Vector2 ddouble dot(Vector3 const &other) const { return Vector2::x * other.x + Vector2::y * other.y + z * other.z; } + inline Vector3 cross(Vector3 const &other) const { + return Vector3(Vector2::y * other.z - z * other.y, + z * other.x - Vector2::x * other.z, + Vector2::x * other.y - Vector2::y * other.x); + } Vector3 min(Vector3 const &other) const { return Vector3(de::min(Vector2::x, other.x), de::min(Vector2::y, other.y), de::min(z, other.z)); @@ -334,6 +383,12 @@ QTextStream &operator << (QTextStream &os, Vector3 const &vec3) * Template class for 4D vectors. * The members are public for convenient access. * + * Note that when mixing 3D and 4D vectors, by default the automatic conversion + * between these simply disregards the @em w component. If the intention is to + * treat 4D vectors as homogeneous, one must explicitly convert to/from 3D + * vectors using Vector4::fromEuclidean() and + * Vector4::toEuclidean(). + * * @ingroup math */ template @@ -341,7 +396,7 @@ class Vector4 : public Vector3 { public: Vector4(Type a = 0, Type b = 0, Type c = 0, Type d = 0) : Vector3(a, b, c), w(d) {} - Vector4(Vector3 const &v3) : Vector3(v3), w(0) {} + Vector4(Vector3 const &v3, Type d = 0) : Vector3(v3), w(d) {} Vector4(Type const *abcd) : Vector3(abcd), w(abcd[3]) {} /// Conversion operator to a float vector. @@ -353,9 +408,16 @@ class Vector4 : public Vector3 return Vector4(Vector3::x, Vector3::y, Vector3::z, w); } Type &operator [] (int index) { - if(index < 3) return Vector3::operator [] (index); - if(index == 3) return w; - throw Error("Vector4::operator[]", QString("Illegal index %1").arg(index)); + DENG2_ASSERT(index >= 0 && index <= 3); + Type *ptrs[] = { &(this->Vector2::x), + &(this->Vector2::y), + &(this->Vector3::z), + &w }; + if(index >= 0 && index < 4) + { + return *ptrs[index]; + } + throw Error("Vector4::operator []", QString("Illegal index %1").arg(index)); } Type const &operator [] (int index) const { return const_cast &>(*this)[index]; @@ -393,6 +455,14 @@ class Vector4 : public Vector3 w -= other.w; return *this; } + inline Vector4 &operator *= (ddouble scalar) { + Vector3::operator *= (scalar); + w *= scalar; + return *this; + } + inline Vector4 &operator /= (ddouble scalar) { + return (*this) *= 1.0 / scalar; + } bool operator > (Vector4 const &other) const { return Vector3::operator > (other) && w > other.w; } @@ -458,6 +528,17 @@ class Vector4 : public Vector3 from >> w; } + static Vector4 fromEuclidean(Vector3 const &vec3) { + return Vector4(vec3, Type(1)); + } + Vector3 toEuclidean() const { + if(w != 0) + { + return Vector3(Vector2::x/w, Vector2::y/w, Vector3::z/w); + } + return Vector3(); + } + public: Type w; }; @@ -620,7 +701,7 @@ inline bool operator != (Vector4 const &a, Vector4 const &b) return !(a == b); } -//@{ +///@{ /// @ingroup types typedef Vector2 Vector2i; ///< 2-component vector of integer values. typedef Vector2 Vector2ui; ///< 2-component vector of unsigned integer values. @@ -635,7 +716,7 @@ typedef Vector4 Vector4i; ///< 4-component vector of integer values. typedef Vector4 Vector4ui; ///< 4-component vector of unsigned integer values. typedef Vector4 Vector4f; ///< 4-component vector of floating point values. typedef Vector4 Vector4d; ///< 4-component vector of high-precision floating point values. -//@} +///@} } // namespace de