Brian Silverman | 10fb0f3 | 2016-03-13 17:05:21 -0400 | [diff] [blame] | 1 | #ifndef AOS_VISION_MATH_VECTOR_H_ |
| 2 | #define AOS_VISION_MATH_VECTOR_H_ |
| 3 | |
| 4 | #include <cmath> |
| 5 | |
| 6 | #include "Eigen/Dense" |
| 7 | |
| 8 | namespace aos { |
| 9 | namespace vision { |
| 10 | |
| 11 | // Represents an n-dimensional vector of doubles with various convenient |
| 12 | // shortcuts for common operations. |
| 13 | // |
| 14 | // This includes overloads of various arithmetic operators for convenience. |
| 15 | // Multiplication by doubles is scalar multiplication and multiplication by |
| 16 | // other vectors is element-wise. |
| 17 | // |
| 18 | // Accessing elements which don't exist for a given size vector, mixing sizes of |
| 19 | // vectors in appropriately, etc are compile-time errors. |
| 20 | template <int size> |
| 21 | class Vector { |
| 22 | public: |
Parker Schuh | 6691f19 | 2017-01-14 17:01:02 -0800 | [diff] [blame^] | 23 | Vector() : data_(::Eigen::Matrix<double, 1, size>::Zero()) {} |
Brian Silverman | 10fb0f3 | 2016-03-13 17:05:21 -0400 | [diff] [blame] | 24 | |
| 25 | Vector(double x, double y) { Set(x, y); } |
| 26 | |
| 27 | Vector(double x, double y, double z) { Set(x, y, z); } |
| 28 | |
| 29 | double Get(int index) const { return data_(index); } |
| 30 | void Set(int index, double value) { data_(index) = value; } |
| 31 | |
| 32 | void Set(double x, double y) { |
| 33 | static_assert(size == 2, "illegal size"); |
| 34 | data_(0) = x; |
| 35 | data_(1) = y; |
| 36 | } |
| 37 | void Set(double x, double y, double z) { |
| 38 | static_assert(size == 3, "illegal size"); |
| 39 | data_(0) = x; |
| 40 | data_(1) = y; |
| 41 | data_(2) = z; |
| 42 | } |
| 43 | void Set(double x, double y, double z, double w) { |
| 44 | static_assert(size == 4, "illegal size"); |
| 45 | data_(0) = x; |
| 46 | data_(1) = y; |
| 47 | data_(2) = z; |
| 48 | data_(3) = w; |
| 49 | } |
| 50 | |
| 51 | double x() const { |
| 52 | static_assert(size >= 1, "illegal size"); |
| 53 | return data_(0); |
| 54 | } |
| 55 | void x(double xX) { |
| 56 | static_assert(size >= 1, "illegal size"); |
| 57 | data_(0) = xX; |
| 58 | } |
| 59 | |
| 60 | double y() const { |
| 61 | static_assert(size >= 2, "illegal size"); |
| 62 | return data_(1); |
| 63 | } |
| 64 | void y(double yY) { |
| 65 | static_assert(size >= 2, "illegal size"); |
| 66 | data_(1) = yY; |
| 67 | } |
| 68 | |
| 69 | double z() const { |
| 70 | static_assert(size >= 3, "illegal size"); |
| 71 | return data_(2); |
| 72 | } |
| 73 | void z(double zZ) { |
| 74 | static_assert(size >= 3, "illegal size"); |
| 75 | data_(2) = zZ; |
| 76 | } |
| 77 | |
| 78 | double w() const { |
| 79 | static_assert(size >= 4, "illegal size"); |
| 80 | return data_(3); |
| 81 | } |
| 82 | void w(double wW) { |
| 83 | static_assert(size >= 4, "illegal size"); |
| 84 | data_(3) = wW; |
| 85 | } |
| 86 | |
| 87 | // Fast part of length. |
| 88 | double MagSqr() const { return data_.squaredNorm(); } |
| 89 | |
| 90 | // Length of the vector. |
| 91 | double Mag() const { return data_.norm(); } |
| 92 | |
| 93 | // Get underlying data structure |
| 94 | ::Eigen::Matrix<double, 1, size> GetData() const { return data_; } |
| 95 | |
| 96 | // Set underlying data structure |
| 97 | void SetData(const ::Eigen::Matrix<double, 1, size> &other) { data_ = other; } |
| 98 | |
| 99 | Vector<size> operator+(const Vector<size> &other) const { |
| 100 | Vector<size> nv = *this; |
| 101 | nv += other; |
| 102 | return nv; |
| 103 | } |
| 104 | Vector<size> operator+=(const Vector<size> &other) { |
| 105 | data_ += other.data_; |
| 106 | return *this; |
| 107 | } |
| 108 | |
| 109 | Vector<size> operator-(const Vector<size> &other) const { |
| 110 | Vector<size> nv = *this; |
| 111 | nv -= other; |
| 112 | return nv; |
| 113 | } |
| 114 | Vector<size> operator-=(const Vector<size> &other) { |
| 115 | data_ -= other.data_; |
| 116 | return *this; |
| 117 | } |
| 118 | |
| 119 | Vector<size> operator*(double other) { |
| 120 | Vector<size> nv = *this; |
| 121 | nv *= other; |
| 122 | return nv; |
| 123 | } |
| 124 | Vector<size> operator*=(double other) { |
| 125 | data_ *= other; |
| 126 | return *this; |
| 127 | } |
| 128 | |
| 129 | Vector<size> operator*(const Vector<size> &other) const { |
| 130 | Vector<size> nv = *this; |
| 131 | nv *= other; |
| 132 | return nv; |
| 133 | } |
| 134 | Vector<size> operator*=(const Vector<size> &other) { |
| 135 | for (int i = 0; i < size; i++) { |
| 136 | Set(i, other.Get(i) * Get(i)); |
| 137 | } |
| 138 | return *this; |
| 139 | } |
| 140 | |
| 141 | bool operator==(const Vector<size> &other) const { |
| 142 | for (int i = 0; i < size; i++) { |
| 143 | if (Get(i) != other.Get(i)) { |
| 144 | return false; |
| 145 | } |
| 146 | } |
| 147 | return true; |
| 148 | } |
| 149 | |
| 150 | double dot(const Vector<size> &other) const { |
| 151 | return data_.dot(other.GetData()); |
| 152 | } |
| 153 | |
| 154 | Vector<size> cross(const Vector<size> &other) const { |
| 155 | Vector<size> nv; |
| 156 | nv.SetData(data_.cross(other.GetData())); |
| 157 | return nv; |
| 158 | } |
| 159 | |
| 160 | // Returns a vector in the same direction as this one with a magnitude of 1. |
| 161 | Vector<size> Normalized() const { |
| 162 | double mag = Mag(); |
| 163 | Vector<size> nv; |
| 164 | for (int i = 0; i < size; i++) { |
| 165 | nv.Set(i, Get(i) / mag); |
| 166 | } |
| 167 | return nv; |
| 168 | } |
| 169 | |
| 170 | // Returns the angle between this vector and the 0 vector. |
| 171 | // Only valid for 2-dimensional vectors. |
| 172 | double AngleToZero() const { |
| 173 | static_assert(size == 2, "illegal size"); |
| 174 | return ::std::atan2(y(), x()); |
| 175 | } |
| 176 | |
| 177 | // Return the angle between this and other. |
Parker Schuh | 6691f19 | 2017-01-14 17:01:02 -0800 | [diff] [blame^] | 178 | double AngleTo(const Vector<size> &other) const { |
Brian Silverman | 10fb0f3 | 2016-03-13 17:05:21 -0400 | [diff] [blame] | 179 | // cos(theta) = u.dot(v) / (u.magnitude() * v.magnitude()) |
| 180 | return ::std::acos(dot(other) / (Mag() * other.Mag())); |
| 181 | } |
| 182 | |
| 183 | // Returns the distance between this and other squared. |
Parker Schuh | 6691f19 | 2017-01-14 17:01:02 -0800 | [diff] [blame^] | 184 | double SquaredDistanceTo(const Vector<size> &other) const { |
Brian Silverman | 10fb0f3 | 2016-03-13 17:05:21 -0400 | [diff] [blame] | 185 | Vector<size> tmp = *this - other; |
| 186 | return tmp.MagSqr(); |
| 187 | } |
| 188 | |
| 189 | private: |
| 190 | // The actual data. |
| 191 | ::Eigen::Matrix<double, 1, size> data_; |
| 192 | }; |
| 193 | |
| 194 | // Returns the cross product of two points. |
| 195 | inline double PointsCrossProduct(const Vector<2> &a, const Vector<2> &b) { |
| 196 | return a.x() * b.y() - a.y() * b.x(); |
| 197 | } |
Parker Schuh | 6691f19 | 2017-01-14 17:01:02 -0800 | [diff] [blame^] | 198 | // scalar multiply |
| 199 | template <int Size> |
| 200 | inline Vector<Size> operator*(const double &lhs, Vector<Size> &rhs) { |
| 201 | Vector<Size> nv; |
| 202 | for (int i = 0; i < Size; i++) { |
| 203 | nv.Set(i, lhs * rhs.Get(i)); |
| 204 | } |
| 205 | return nv; |
| 206 | } |
Brian Silverman | 10fb0f3 | 2016-03-13 17:05:21 -0400 | [diff] [blame] | 207 | |
| 208 | } // namespace vision |
| 209 | } // namespace aos |
| 210 | |
| 211 | #endif // AOS_VISION_MATH_VECTOR_H_ |