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 |
Austin Schuh | e6cfbe3 | 2019-03-10 18:05:57 -0700 | [diff] [blame] | 94 | // TODO(austin): Everyone uses column not row vectors. |
Brian Silverman | 10fb0f3 | 2016-03-13 17:05:21 -0400 | [diff] [blame] | 95 | ::Eigen::Matrix<double, 1, size> GetData() const { return data_; } |
| 96 | |
| 97 | // Set underlying data structure |
| 98 | void SetData(const ::Eigen::Matrix<double, 1, size> &other) { data_ = other; } |
| 99 | |
| 100 | Vector<size> operator+(const Vector<size> &other) const { |
| 101 | Vector<size> nv = *this; |
| 102 | nv += other; |
| 103 | return nv; |
| 104 | } |
| 105 | Vector<size> operator+=(const Vector<size> &other) { |
| 106 | data_ += other.data_; |
| 107 | return *this; |
| 108 | } |
| 109 | |
| 110 | Vector<size> operator-(const Vector<size> &other) const { |
| 111 | Vector<size> nv = *this; |
| 112 | nv -= other; |
| 113 | return nv; |
| 114 | } |
| 115 | Vector<size> operator-=(const Vector<size> &other) { |
| 116 | data_ -= other.data_; |
| 117 | return *this; |
| 118 | } |
| 119 | |
| 120 | Vector<size> operator*(double other) { |
| 121 | Vector<size> nv = *this; |
| 122 | nv *= other; |
| 123 | return nv; |
| 124 | } |
| 125 | Vector<size> operator*=(double other) { |
| 126 | data_ *= other; |
| 127 | return *this; |
| 128 | } |
| 129 | |
| 130 | Vector<size> operator*(const Vector<size> &other) const { |
| 131 | Vector<size> nv = *this; |
| 132 | nv *= other; |
| 133 | return nv; |
| 134 | } |
| 135 | Vector<size> operator*=(const Vector<size> &other) { |
| 136 | for (int i = 0; i < size; i++) { |
| 137 | Set(i, other.Get(i) * Get(i)); |
| 138 | } |
| 139 | return *this; |
| 140 | } |
| 141 | |
| 142 | bool operator==(const Vector<size> &other) const { |
| 143 | for (int i = 0; i < size; i++) { |
| 144 | if (Get(i) != other.Get(i)) { |
| 145 | return false; |
| 146 | } |
| 147 | } |
| 148 | return true; |
| 149 | } |
| 150 | |
| 151 | double dot(const Vector<size> &other) const { |
| 152 | return data_.dot(other.GetData()); |
| 153 | } |
| 154 | |
| 155 | Vector<size> cross(const Vector<size> &other) const { |
| 156 | Vector<size> nv; |
| 157 | nv.SetData(data_.cross(other.GetData())); |
| 158 | return nv; |
| 159 | } |
| 160 | |
| 161 | // Returns a vector in the same direction as this one with a magnitude of 1. |
| 162 | Vector<size> Normalized() const { |
| 163 | double mag = Mag(); |
| 164 | Vector<size> nv; |
| 165 | for (int i = 0; i < size; i++) { |
| 166 | nv.Set(i, Get(i) / mag); |
| 167 | } |
| 168 | return nv; |
| 169 | } |
| 170 | |
| 171 | // Returns the angle between this vector and the 0 vector. |
| 172 | // Only valid for 2-dimensional vectors. |
| 173 | double AngleToZero() const { |
| 174 | static_assert(size == 2, "illegal size"); |
| 175 | return ::std::atan2(y(), x()); |
| 176 | } |
| 177 | |
| 178 | // Return the angle between this and other. |
Parker Schuh | 6691f19 | 2017-01-14 17:01:02 -0800 | [diff] [blame] | 179 | double AngleTo(const Vector<size> &other) const { |
Brian Silverman | 10fb0f3 | 2016-03-13 17:05:21 -0400 | [diff] [blame] | 180 | // cos(theta) = u.dot(v) / (u.magnitude() * v.magnitude()) |
| 181 | return ::std::acos(dot(other) / (Mag() * other.Mag())); |
| 182 | } |
| 183 | |
| 184 | // Returns the distance between this and other squared. |
Parker Schuh | 6691f19 | 2017-01-14 17:01:02 -0800 | [diff] [blame] | 185 | double SquaredDistanceTo(const Vector<size> &other) const { |
Brian Silverman | 10fb0f3 | 2016-03-13 17:05:21 -0400 | [diff] [blame] | 186 | Vector<size> tmp = *this - other; |
| 187 | return tmp.MagSqr(); |
| 188 | } |
| 189 | |
Parker Schuh | 02f13f6 | 2019-02-16 16:42:41 -0800 | [diff] [blame] | 190 | // Returns the distance between this and other. |
| 191 | double DistanceTo(const Vector<size> &other) const { |
| 192 | return std::sqrt(SquaredDistanceTo(other)); |
| 193 | } |
| 194 | |
Brian Silverman | 10fb0f3 | 2016-03-13 17:05:21 -0400 | [diff] [blame] | 195 | private: |
| 196 | // The actual data. |
| 197 | ::Eigen::Matrix<double, 1, size> data_; |
| 198 | }; |
| 199 | |
| 200 | // Returns the cross product of two points. |
| 201 | inline double PointsCrossProduct(const Vector<2> &a, const Vector<2> &b) { |
| 202 | return a.x() * b.y() - a.y() * b.x(); |
| 203 | } |
Parker Schuh | 02f13f6 | 2019-02-16 16:42:41 -0800 | [diff] [blame] | 204 | |
| 205 | // Rotates along the z, y, and then x axis (all radians). |
| 206 | inline Vector<3> Rotate(double rx, double ry, double rz, const Vector<3> vec) { |
| 207 | ::Eigen::AngleAxis<double> ax(rx, ::Eigen::Vector3d(1.0, 0.0, 0.0)); |
| 208 | ::Eigen::AngleAxis<double> ay(ry, ::Eigen::Vector3d(0.0, 1.0, 0.0)); |
| 209 | ::Eigen::AngleAxis<double> az(rz, ::Eigen::Vector3d(0.0, 0.0, 1.0)); |
| 210 | Vector<3> result; |
| 211 | result.SetData(ax * ay * az * vec.GetData()); |
| 212 | return result; |
| 213 | } |
| 214 | |
Parker Schuh | 6691f19 | 2017-01-14 17:01:02 -0800 | [diff] [blame] | 215 | // scalar multiply |
| 216 | template <int Size> |
| 217 | inline Vector<Size> operator*(const double &lhs, Vector<Size> &rhs) { |
| 218 | Vector<Size> nv; |
| 219 | for (int i = 0; i < Size; i++) { |
| 220 | nv.Set(i, lhs * rhs.Get(i)); |
| 221 | } |
| 222 | return nv; |
| 223 | } |
Brian Silverman | 10fb0f3 | 2016-03-13 17:05:21 -0400 | [diff] [blame] | 224 | |
| 225 | } // namespace vision |
| 226 | } // namespace aos |
| 227 | |
| 228 | #endif // AOS_VISION_MATH_VECTOR_H_ |