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