LCOV - code coverage report
Current view: top level - source/maths - FixedVector2D.h (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 83 91 91.2 %
Date: 2023-01-19 00:18:29 Functions: 20 23 87.0 %

          Line data    Source code
       1             : /* Copyright (C) 2020 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #ifndef INCLUDED_FIXED_VECTOR2D
      19             : #define INCLUDED_FIXED_VECTOR2D
      20             : 
      21             : #include "maths/Fixed.h"
      22             : #include "maths/Sqrt.h"
      23             : 
      24             : class CFixedVector2D
      25             : {
      26             : public:
      27             :     fixed X, Y;
      28             : 
      29         188 :     CFixedVector2D() { }
      30       10320 :     CFixedVector2D(fixed X, fixed Y) : X(X), Y(Y) { }
      31             : 
      32             :     /// Vector equality
      33          17 :     bool operator==(const CFixedVector2D& v) const
      34             :     {
      35          17 :         return (X == v.X && Y == v.Y);
      36             :     }
      37             : 
      38             :     /// Vector inequality
      39           0 :     bool operator!=(const CFixedVector2D& v) const
      40             :     {
      41           0 :         return (X != v.X || Y != v.Y);
      42             :     }
      43             : 
      44             :     /// Vector addition
      45         580 :     CFixedVector2D operator+(const CFixedVector2D& v) const
      46             :     {
      47         580 :         return CFixedVector2D(X + v.X, Y + v.Y);
      48             :     }
      49             : 
      50             :     /// Vector subtraction
      51        2412 :     CFixedVector2D operator-(const CFixedVector2D& v) const
      52             :     {
      53        2412 :         return CFixedVector2D(X - v.X, Y - v.Y);
      54             :     }
      55             : 
      56             :     /// Negation
      57          46 :     CFixedVector2D operator-() const
      58             :     {
      59          46 :         return CFixedVector2D(-X, -Y);
      60             :     }
      61             : 
      62             :     /// Vector addition
      63           1 :     CFixedVector2D& operator+=(const CFixedVector2D& v)
      64             :     {
      65           1 :         *this = *this + v;
      66           1 :         return *this;
      67             :     }
      68             : 
      69             :     /// Vector subtraction
      70           3 :     CFixedVector2D& operator-=(const CFixedVector2D& v)
      71             :     {
      72           3 :         *this = *this - v;
      73           3 :         return *this;
      74             :     }
      75             : 
      76             :     /// Scalar multiplication by an integer
      77          64 :     CFixedVector2D operator*(int n) const
      78             :     {
      79          64 :         return CFixedVector2D(X*n, Y*n);
      80             :     }
      81             : 
      82             :     /// Scalar division by an integer. Must not have n == 0.
      83           0 :     CFixedVector2D operator/(int n) const
      84             :     {
      85           0 :         return CFixedVector2D(X/n, Y/n);
      86             :     }
      87             : 
      88             :     /**
      89             :      * Multiply by a CFixed. Likely to overflow if both numbers are large,
      90             :      * so we use an ugly name instead of operator* to make it obvious.
      91             :      */
      92         936 :     CFixedVector2D Multiply(fixed n) const
      93             :     {
      94         936 :         return CFixedVector2D(X.Multiply(n), Y.Multiply(n));
      95             :     }
      96             : 
      97             :     /**
      98             :      * Returns the length of the vector.
      99             :      * Will not overflow if the result can be represented as type 'fixed'.
     100             :      */
     101         208 :     fixed Length() const
     102             :     {
     103             :         // Do intermediate calculations with 64-bit ints to avoid overflows
     104         208 :         u64 xx = SQUARE_U64_FIXED(X);
     105         208 :         u64 yy = SQUARE_U64_FIXED(Y);
     106         208 :         u64 d2 = xx + yy;
     107         208 :         CheckUnsignedAdditionOverflow(d2, xx, L"Overflow in CFixedVector2D::Length() part 1")
     108             : 
     109         208 :         u32 d = isqrt64(d2);
     110             : 
     111         208 :         CheckU32CastOverflow(d, i32, L"Overflow in CFixedVector2D::Length() part 2")
     112         208 :         fixed r;
     113         208 :         r.SetInternalValue(static_cast<i32>(d));
     114         208 :         return r;
     115             :     }
     116             : 
     117             :     /**
     118             :      * Returns -1, 0, +1 depending on whether length is less/equal/greater
     119             :      * than the argument.
     120             :      * Avoids sqrting and overflowing.
     121             :      */
     122        1763 :     int CompareLength(fixed cmp) const
     123             :     {
     124        1763 :         u64 d2 = SQUARE_U64_FIXED(X) + SQUARE_U64_FIXED(Y); // d2 <= 2^63 (no overflow)
     125        1763 :         u64 cmpSquared = SQUARE_U64_FIXED(cmp);
     126             : 
     127        1763 :         if (d2 < cmpSquared)
     128          95 :             return -1;
     129             : 
     130        1668 :         if (d2 > cmpSquared)
     131        1660 :             return +1;
     132             : 
     133           8 :         return 0;
     134             :     }
     135             : 
     136             :     /**
     137             :      * Same as above, but avoids squaring the compared value.
     138             :      * The argument must be the result of an SQUARE_U64_FIXED operation.
     139             :      */
     140           5 :     int CompareLengthSquared(u64 cmpSquared) const
     141             :     {
     142           5 :         u64 d2 = SQUARE_U64_FIXED(X) + SQUARE_U64_FIXED(Y); // d2 <= 2^63 (no overflow)
     143             : 
     144           5 :         if (d2 < cmpSquared)
     145           2 :             return -1;
     146             : 
     147           3 :         if (d2 > cmpSquared)
     148           2 :             return +1;
     149             : 
     150           1 :         return 0;
     151             :     }
     152             : 
     153             :     /**
     154             :      * Returns -1, 0, +1 depending on whether length is less/equal/greater
     155             :      * than the argument's length.
     156             :      * Avoids sqrting and overflowing.
     157             :      */
     158           3 :     int CompareLength(const CFixedVector2D& other) const
     159             :     {
     160           3 :         u64 d2 = SQUARE_U64_FIXED(X) + SQUARE_U64_FIXED(Y);
     161           3 :         u64 od2 = SQUARE_U64_FIXED(other.X) + SQUARE_U64_FIXED(other.Y);
     162             : 
     163           3 :         if (d2 < od2)
     164           1 :             return -1;
     165             : 
     166           2 :         if (d2 > od2)
     167           1 :             return +1;
     168             : 
     169           1 :         return 0;
     170             :     }
     171             : 
     172           5 :     bool IsZero() const
     173             :     {
     174           5 :         return X.IsZero() && Y.IsZero();
     175             :     }
     176             : 
     177             :     /**
     178             :      * Normalize the vector so that length is close to 1.
     179             :      * If length is 0, does nothing.
     180             :      */
     181           4 :     void Normalize()
     182             :     {
     183           4 :         if (!IsZero())
     184             :         {
     185           3 :             fixed l = Length();
     186           3 :             X = X / l;
     187           3 :             Y = Y / l;
     188             :         }
     189           4 :     }
     190             : 
     191             :     /**
     192             :      * Normalize the vector so that length is close to n.
     193             :      * If length is 0, does nothing.
     194             :      */
     195           9 :     void Normalize(fixed n)
     196             :     {
     197           9 :         fixed l = Length();
     198           9 :         if (!l.IsZero())
     199             :         {
     200           8 :             X = X.MulDiv(n, l);
     201           8 :             Y = Y.MulDiv(n, l);
     202             :         }
     203           9 :     }
     204             : 
     205             :     /**
     206             :      * Compute the dot product of this vector with another.
     207             :      * Likely to overflow if both vectors are large-ish (around the 200 range).
     208             :      */
     209         436 :     fixed Dot(const CFixedVector2D& v) const
     210             :     {
     211         436 :         i64 x = MUL_I64_I32_I32(X.GetInternalValue(), v.X.GetInternalValue());
     212         436 :         i64 y = MUL_I64_I32_I32(Y.GetInternalValue(), v.Y.GetInternalValue());
     213         436 :         CheckSignedAdditionOverflow(i64, x, y, L"Overflow in CFixedVector2D::Dot() part 1", L"Underflow in CFixedVector2D::Dot() part 1")
     214         436 :         i64 sum = x + y;
     215         436 :         sum >>= fixed::fract_bits;
     216             : 
     217         436 :         CheckCastOverflow(sum, i32, L"Overflow in CFixedVector2D::Dot() part 2", L"Underflow in CFixedVector2D::Dot() part 2")
     218         436 :         fixed ret;
     219         436 :         ret.SetInternalValue(static_cast<i32>(sum));
     220         436 :         return ret;
     221             :     }
     222             : 
     223             :     /**
     224             :      * @return -1, 0 or 1 if this and @v face respectively opposite directions, perpendicular, or same directions.
     225             :      */
     226          60 :     int RelativeOrientation(const CFixedVector2D& v) const
     227             :     {
     228          60 :         i64 x = MUL_I64_I32_I32(X.GetInternalValue(), v.X.GetInternalValue());
     229          60 :         i64 y = MUL_I64_I32_I32(Y.GetInternalValue(), v.Y.GetInternalValue());
     230          60 :         return x > -y ? 1 : x < -y ? -1 : 0;
     231             :     }
     232             : 
     233          44 :     CFixedVector2D Perpendicular() const
     234             :     {
     235          44 :         return CFixedVector2D(Y, -X);
     236             :     }
     237             : 
     238             :     /**
     239             :      * Rotate the vector by the given angle (anticlockwise).
     240             :      */
     241           0 :     CFixedVector2D Rotate(fixed angle) const
     242             :     {
     243           0 :         fixed s, c;
     244           0 :         sincos_approx(angle, s, c);
     245           0 :         return CFixedVector2D(X.Multiply(c) + Y.Multiply(s), Y.Multiply(c) - X.Multiply(s));
     246             :     }
     247             : };
     248             : 
     249             : #endif // INCLUDED_FIXED_VECTOR2D

Generated by: LCOV version 1.13