diff --git a/Angle.h b/Angle.h index 0c7db51..31fc88a 100644 --- a/Angle.h +++ b/Angle.h @@ -11,7 +11,7 @@ template class AngleOf { public: AngleOf(){}; AngleOf(T v) : value(v) {} - operator T() { return value; } + operator T() const { return value; } static AngleOf Rad2Deg; static AngleOf Deg2Rad; diff --git a/Polar.cpp b/Polar.cpp index 5332b24..12b09bd 100644 --- a/Polar.cpp +++ b/Polar.cpp @@ -90,7 +90,7 @@ Polar Polar::operator/(const float &f) { this->angle); // Polar(this->angle, this->distance / f); } -float Polar::Distance(Polar &v1, Polar &v2) { +float Polar::Distance(const Polar &v1, const Polar &v2) { float d = Angle::CosineRuleSide(v1.distance, v2.distance, (float)v2.angle - (float)v1.angle); return d; diff --git a/Polar.h b/Polar.h index 9fdb50e..e95fd56 100644 --- a/Polar.h +++ b/Polar.h @@ -12,18 +12,11 @@ namespace Passer { struct Vector2; struct Spherical; -/// -/// A polar vector -/// +/// @brief A polar vector /// This will use the polar coordinate system consisting of a angle from a /// reference direction and a distance. struct Polar { public: - /// - /// The distance in meters - /// - /// The distance should never be negative - /// @brief The distance in meters /// @remark The distance shall never be negative float distance; @@ -52,6 +45,11 @@ public: /// @brief A polar vector with zero degrees and distance const static Polar zero; + /// @brief Equality test to another vector + /// @param v The vector to check against + /// @return true: if it is identical to the given vector + /// @note This uses float comparison to check equality which may have strange + /// effects. Equality on floats should be avoided. bool operator==(const Polar &v); /// @brief Negate the vector @@ -62,48 +60,36 @@ public: /// @param v The vector to subtract /// @return The result of the subtraction Polar operator-(Polar &v); - - /// - /// Add another polar vector to this polar vector - /// - /// The vector to add - /// The result of adding the vector + /// @brief Add a polar vector to this vector + /// @param v The vector to add + /// @return The result of the addition Polar operator+(Polar &v); + /// @brief Scale the vector uniformly up + /// @param f The scaling factor + /// @return The scaled vector + /// @remark This operation will scale the distance of the vector. The angle + /// will be unaffected. + Polar operator*(float f) const; + /// @brief Scale the vector uniformly down + /// @param f The scaling factor + /// @return The scaled factor + /// @remark This operation will scale the distance of the vector. The angle + /// will be unaffected. + Polar operator/(const float &f); - /// - /// Scale the vector uniformly up - /// - /// The scaling factor - /// The scaled vector - /// This operation will scale the distance of the vector. The angle will be - /// unaffected. - Polar operator*(float factor) const; + /// @brief The distance between two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The distance between the two vectors + static float Distance(const Polar &v1, const Polar &v2); - /// - /// Scale the vector uniformly down - /// - /// The scaling factor - /// The scaled vector - /// This operation will scale the distance of the vector. The angle will be - /// unaffected. - Polar operator/(const float &factor); - - /// - /// The distance between two vectors - /// - /// The first vector - /// The second vector - /// The distance between the two vectors - static float Distance(Polar &v1, Polar &v2); - - /// - /// Rotate the vector - /// - /// The vector to rotate - /// Angle in radias to rotate - /// The rotated vector - static Polar Rotate(Polar v, Angle angle); + /// @brief Rotate a vector + /// @param v The vector to rotate + /// @param a The angle in degreesto rotate + /// @return The rotated vector + static Polar Rotate(Polar v, Angle a); }; + } // namespace Passer using namespace Passer; diff --git a/Vector2.cpp b/Vector2.cpp index 6a1a03a..0aeaba1 100644 --- a/Vector2.cpp +++ b/Vector2.cpp @@ -17,22 +17,18 @@ Vector2::Vector2() { x = 0; y = 0; } - Vector2::Vector2(float _x, float _y) { x = _x; y = _y; } - Vector2::Vector2(Vec2 v) { x = v.x; y = v.y; } - Vector2::Vector2(Vector3 v) { x = v.x; y = v.z; } - Vector2::Vector2(Polar p) { float horizontalRad = p.angle * Angle::Deg2Rad; float cosHorizontal = cosf(horizontalRad); @@ -61,7 +57,6 @@ float Vector2::Magnitude(const Vector2 &a) { return sqrtf(a.x * a.x + a.y * a.y); } float Vector2::magnitude() const { return (float)sqrtf(x * x + y * y); } - float Vector2::SqrMagnitude(const Vector2 &a) { return a.x * a.x + a.y * a.y; } float Vector2::sqrMagnitude() const { return (x * x + y * y); } @@ -82,12 +77,11 @@ Vector2 Vector2::normalized() const { return result; } +Vector2 Vector2::operator-() { return Vector2(-this->x, -this->y); } + Vector2 Vector2::operator-(const Vector2 &v2) const { return Vector2(this->x - v2.x, this->y - v2.y); } - -Vector2 Vector2::operator-() { return Vector2(-this->x, -this->y); } - Vector2 Vector2::operator+(const Vector2 &v2) const { return Vector2(this->x + v2.x, this->y + v2.y); } @@ -95,30 +89,27 @@ Vector2 Vector2::operator+(const Vector2 &v2) const { Vector2 Vector2::Scale(const Vector2 &p1, const Vector2 &p2) { return Vector2(p1.x * p2.x, p1.y * p2.y); } - -Vector2 Vector2::operator*(float f) const { +Vector2 Vector2::operator*(const float &f) const { return Vector2(this->x * f, this->y * f); } - -Vector2 Vector2::operator/(const float &d) { - return Vector2(this->x / d, this->y / d); +Vector2 Vector2::operator/(const float &f) const { + return Vector2(this->x / f, this->y / f); } float Vector2::Dot(const Vector2 &v1, const Vector2 &v2) { return v1.x * v2.x + v1.y * v2.y; } -float Vector2::Distance(const Vector2 &p1, const Vector2 &p2) { - return Magnitude(p1 - p2); +float Vector2::Distance(const Vector2 &v1, const Vector2 &v2) { + return Magnitude(v1 - v2); } -float Vector2::Angle(Vector2 from, Vector2 to) { - return (float)fabs(SignedAngle(from, to)); +float Vector2::Angle(const Vector2 &v1, const Vector2 &v2) { + return (float)fabs(SignedAngle(v1, v2)); } - -float Vector2::SignedAngle(Vector2 from, Vector2 to) { - float sqrMagFrom = from.sqrMagnitude(); - float sqrMagTo = to.sqrMagnitude(); +float Vector2::SignedAngle(const Vector2 &v1, const Vector2 &v2) { + float sqrMagFrom = v1.sqrMagnitude(); + float sqrMagTo = v2.sqrMagnitude(); if (sqrMagFrom == 0 || sqrMagTo == 0) return 0; @@ -129,13 +120,13 @@ float Vector2::SignedAngle(Vector2 from, Vector2 to) { return nanf(""); #endif - float angleFrom = atan2(from.y, from.x); - float angleTo = atan2(to.y, to.x); + float angleFrom = atan2(v1.y, v1.x); + float angleTo = atan2(v2.y, v2.x); return -(angleTo - angleFrom) * Angle::Rad2Deg; } -Vector2 Vector2::Rotate(Vector2 v, float angle) { - float angleRad = angle * Angle::Deg2Rad; +Vector2 Vector2::Rotate(const Vector2 &v, const float &a) { + float angleRad = a * Angle::Deg2Rad; #if defined(AVR) float sinValue = sin(angleRad); float cosValue = cos(angleRad); // * Angle::Deg2Rad); @@ -146,12 +137,12 @@ Vector2 Vector2::Rotate(Vector2 v, float angle) { float tx = v.x; float ty = v.y; - v.x = (cosValue * tx) - (sinValue * ty); - v.y = (sinValue * tx) + (cosValue * ty); - return v; + Vector2 r = Vector2((cosValue * tx) - (sinValue * ty), + (sinValue * tx) + (cosValue * ty)); + return r; } -Vector2 Vector2::Lerp(Vector2 from, Vector2 to, float f) { - Vector2 v = from + (to - from) * f; +Vector2 Vector2::Lerp(const Vector2 &v1, const Vector2 &v2, const float f) { + Vector2 v = v1 + (v2 - v1) * f; return v; } diff --git a/Vector2.h b/Vector2.h index 7fd361c..fbf5d3e 100644 --- a/Vector2.h +++ b/Vector2.h @@ -29,221 +29,163 @@ namespace Passer { struct Vector3; struct Polar; -/// -/// A 2-dimensional vector -/// -/// This uses the right-handed coordinate system. +/// @brief A 2=dimensional vector +/// @remark This uses the right=handed carthesian coordinate system. +/// @note This implementation intentionally avoids the use of x and y struct Vector2 : Vec2 { public: - /// - /// Create a new 2-dimensinal zero vector - /// + /// @brief A new 2-dimensional zero vector Vector2(); - /// - /// Create a new 2-dimensional vector - /// - /// x axis value - /// y axis value - Vector2(float x, float y); - /// - /// Create a vector from C-style Vec2 - /// - /// The C-style Vec + /// @brief A new 2-dimensional vector + /// @param sideward The sideward value + /// @param forward The forward value + Vector2(float sideward, float forward); + /// @brief A vector created from a C-style Vec2 + /// @param v The C-syle Vec2 Vector2(Vec2 v); - - /// - /// Convert a Vector3 to a Vector3 - /// - /// The 3D vector + /// @brief Convert a Vector3 to a Vector2 + /// @param v The 3D vector + /// @note This will project the vector to the horizontal plane Vector2(Vector3 v); + /// @brief Convert a Polar vector to a 2-dimensional vector + /// @param v The vector in polar coordinates + Vector2(Polar v); - Vector2(Polar p); - - /// - /// Vector2 destructor - /// - /// A vector with zero for all axis - /// + /// @brief A vector with zero for all axis const static Vector2 zero; - /// - /// A vector with values (1, 1) - /// + /// @brief A vector with one for all axis const static Vector2 one; - /// - /// A vector with values (1, 0) - /// - /// + /// @brief A normalized right-oriented vector const static Vector2 right; - /// - /// A vector3 with values (-1, 0) - /// + /// @brief A normalized left-oriented vector const static Vector2 left; - /// - /// A vector with values (0, 1) - /// + /// @brief A normalized up-oriented vector + /// @note This is equal to Vector2::forward const static Vector2 up; - /// - /// A vector with values (0, -1) - /// + /// @brief A normalized down-oriented vector + /// @note This is equal to Vector2::down const static Vector2 down; - /// - /// A vector with values (0, 1) - /// + /// @brief A normalized forward-oriented vector + /// @note This is equal to Vector2::up const static Vector2 forward; - /// - /// A vector with values (0, -1) - /// + /// @brief A normalized back-oriented vector + /// @note This is equal to Vector2::down const static Vector2 back; /// @brief Check if this vector to the given vector - /// @param vector The vector to check against + /// @param v The vector to check against /// @return true if it is identical to the given vector - /// @note This uses float comparison to check equality which may - /// have strange effects. Equality on floats should be avoided. - bool operator==(const Vector2 &vector); + /// @note This uses float comparison to check equality which may have strange + /// effects. Equality on floats should be avoided. + bool operator==(const Vector2 &v); - /// - /// The length of a vector - /// - /// The vector for which you need the length - /// The length of the given vector - static float Magnitude(const Vector2 &vector); - /// - /// The length of this vector - /// - /// The length of this vector + /// @brief The vector length + /// @param v The vector for which you need the length + /// @return The vector length + static float Magnitude(const Vector2 &v); + /// @brief The vector length + /// @return The vector length float magnitude() const; - /// - /// The squared length of a vector - /// - /// The vector for which you need the squared - /// length The squatred length The squared length - /// is computationally simpler than the real length. Think of Pythagoras A^2 + - /// B^2 = C^2. This leaves out the calculation of the squared root of C. - static float SqrMagnitude(const Vector2 &vector); - /// - /// The squared length of this vector - /// - /// The squared length - /// The squared length is computationally simpler than the real length. - /// Think of Pythagoras A^2 + B^2 = C^2. - /// This leaves out the calculation of the squared root of C. + /// @brief The squared vector length + /// @param v The vector for which you need the squared length + /// @return The squared vector length + /// @remark The squared length is computationally simpler than the real + /// length. Think of Pythagoras A^2 + B^2 = C^2. This prevents the calculation + /// of the squared root of C. + static float SqrMagnitude(const Vector2 &v); + /// @brief The squared vector length + /// @return The squared vector length + /// @remark The squared length is computationally simpler than the real + /// length. Think of Pythagoras A^2 + B^2 = C^2. This prevents the calculation + /// of the squared root of C. float sqrMagnitude() const; - /// - /// Connvert a vector to a length of 1 - /// - /// The vector to convert - /// The vector with length 1 - static Vector2 Normalize(Vector2 vector); - /// - /// Convert the vector to a length of a - /// - /// The vector with length 1 + + /// @brief Convert the vector to a length of 1 + /// @param v The vector to convert + /// @return The vector normalized to a length of 1 + static Vector2 Normalize(Vector2 v); + /// @brief Convert the vector to a length 1 + /// @return The vector normalized to a length of 1 Vector2 normalized() const; - /// - /// Negate the vector - /// - /// The negated vector - /// This will result in a vector pointing in the opposite direction + /// @brief Negate the vector such that it points in the opposite direction + /// @return The negated vector Vector2 operator-(); - /// - /// Subtract a vector from this vector - /// - /// The vector to subtract from this vector - /// The result of the subtraction - Vector2 operator-(const Vector2 &vector) const; - /// - /// Add another vector to this vector - /// - /// The vector to add - /// The result of adding the vector - Vector2 operator+(const Vector2 &vector2) const; + /// @brief Subtract a vector from this vector + /// @param v The vector to subtract from this vector + /// @return The result of the subtraction + Vector2 operator-(const Vector2 &v) const; + /// @brief Add a vector to this vector + /// @param v The vector to add to this vector + /// @return The result of the addition + Vector2 operator+(const Vector2 &v) const; - /// - /// Scale a vector using another vector - /// - /// The vector to scale - /// A vector with scaling factors - /// The scaled vector - /// Each component of the vector v1 will be multiplied with the - /// component from the scaling vector v2. - static Vector2 Scale(const Vector2 &vector1, const Vector2 &vector2); - /// - /// Scale a vector uniformly up - /// - /// The scaling factor - /// The scaled vector - /// Each component of the vector will be multipled with the same factor. - Vector2 operator*(float factor) const; - /// - /// Scale a vector uniformy down - /// - /// The scaling factor - /// The scaled vector - /// Each componet of the vector will be divided by the same factor. - Vector2 operator/(const float &factor); + /// @brief Scale a vector using another vector + /// @param v1 The vector to scale + /// @param v2 A vector with the scaling factors + /// @return The scaled vector + /// @remark Each component of the vector v1 will be multiplied with the + /// matching component from the scaling vector v2. + static Vector2 Scale(const Vector2 &v1, const Vector2 &v2); + /// @brief Scale the vector uniformly up + /// @param f The scaling factor + /// @return The scaled vector + /// @remark Each component of the vector will be multipled with the same + /// factor f. + Vector2 operator*(const float &f) const; + /// @brief Scale the vector uniformly down + /// @param f The scaling factor + /// @return The scaled vector + /// @remark Each componet of the vector will be divided by the same factor. + Vector2 operator/(const float &f) const; - /// - /// The dot product of two vectors - /// - /// The first vector - /// The second vector - /// The dot product of the two vectors - static float Dot(const Vector2 &vector1, const Vector2 &vector2); + /// @brief The dot product of two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The dot product of the two vectors + static float Dot(const Vector2 &v1, const Vector2 &v2); - /// - /// The distance between two vectors - /// - /// The first vector - /// The second vectors - /// The distance between the two vectors - static float Distance(const Vector2 &vector1, const Vector2 &vector2); + /// @brief The distance between two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The distance between the two vectors + static float Distance(const Vector2 &v1, const Vector2 &v2); - /// - /// Calculate the angle between two vectors - /// - /// The first vector - /// The second vector - /// The angle - /// This reterns an unsigned angle which is the shortest distance - /// between the two vectors. Use Vector3::SignedAngle if a - /// signed angle is needed. - static float Angle(Vector2 vector1, Vector2 vector2); + /// @brief The angle between two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The angle between the two vectors + /// @remark This reterns an unsigned angle which is the shortest distance + /// between the two vectors. Use Vector2::SignedAngle if a signed angle is + /// needed. + static float Angle(const Vector2 &v1, const Vector2 &v2); + /// @brief The signed angle between two vectors + /// @param v1 The starting vector + /// @param v2 The ending vector + /// @return The signed angle between the two vectors + static float SignedAngle(const Vector2 &v1, const Vector2 &v2); - /// - /// Calculate the angle between two vectors rotation around an axis. - /// - /// The starting vector - /// The ending vector - /// The axis to rotate around - /// The signed angle - static float SignedAngle(Vector2 from, Vector2 to); + /// @brief Rotate the vector + /// @param v The vector to rotate + /// @param a The angle in degrees to rotate + /// @return The rotated vector + static Vector2 Rotate(const Vector2 &v, const float &a); - /// - /// Rotate the vector - /// - /// The vector to rotate - /// Angle in radias to rotate - /// The rotated vector - static Vector2 Rotate(Vector2 v, float angle); - - /// - /// Lerp between two vectors - /// - /// The from vector - /// The to vector - /// The interpolation distance (0..1) - /// The lerped vector - /// The factor f is unclamped. Value 0 matches the *from* vector, Value 1 - /// matches the *to* vector Value -1 is *from* vector minus the difference - /// between *from* and *to* etc. - static Vector2 Lerp(Vector2 from, Vector2 to, float f); + /// @brief Lerp (linear interpolation) between two vectors + /// @param v1 The starting vector + /// @param v2 The end vector + /// @param f The interpolation distance + /// @return The lerped vector + /// @remark The factor f is unclamped. Value 0 matches the vector *v1*, Value + /// 1 matches vector *v2*. Value -1 is vector *v1* minus the difference + /// between *v1* and *v2* etc. + static Vector2 Lerp(const Vector2 &v1, const Vector2 &v2, const float f); }; + } // namespace Passer using namespace Passer; diff --git a/test/Polar_test.cc b/test/Polar_test.cc index 7ef43ca..2598e7b 100644 --- a/test/Polar_test.cc +++ b/test/Polar_test.cc @@ -105,4 +105,57 @@ TEST(Polar, Subtraction) { EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Subtraction(0 0)"; } +TEST(Polar, Addition) { + Polar v1 = Polar(4, 45); + Polar v2 = Polar(1, -90); + Polar r = Polar::zero; + + r = v1 - v2; + // don't know what to expect yet + + v2 = Polar::zero; + r = v1 + v2; + EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0)"; +} + +TEST(Polar, Scale_Multiply) { + Polar v1 = Polar(4, 45); + Polar r = Polar::zero; + + r = v1 * 2.0f; + EXPECT_FLOAT_EQ(r.distance, v1.distance * 2) << "ScaleMult(4 45, 2)"; + EXPECT_FLOAT_EQ(r.angle, v1.angle) << "ScaleMult(4 45, 2)"; +} + +TEST(Polar, Scale_Divide) { + Polar v1 = Polar(4, 45); + Polar r = Polar::zero; + + r = v1 / 2.0f; + EXPECT_FLOAT_EQ(r.distance, v1.distance / 2) << "ScaleDiv(4 45, 2)"; + EXPECT_FLOAT_EQ(r.angle, v1.angle) << "ScaleDiv(4 45, 2)"; +} + +TEST(Polar, Distance) { + Polar v1 = Polar(4, 45); + Polar v2 = Polar(1, -90); + float d = 0; + + d = Polar::Distance(v1, v2); + // don't know what to expect yet + + v2 = Polar::zero; + d = Polar::Distance(v1, v2); + EXPECT_FLOAT_EQ(d, v1.distance) << "Distance(4 45, zero)"; +} + +TEST(Polar, Rotate) { + Polar v = Polar(4, 45); + Polar r = Polar::zero; + + r = Polar::Rotate(v, 45); + EXPECT_FLOAT_EQ(r.distance, v.distance) << "Rotate(4 45, 45)"; + EXPECT_FLOAT_EQ(r.angle, 90.0f) << "Rotate(4 45, 45)"; +} + #endif \ No newline at end of file