blob: ce29901aea9b55d4e4e7e14e803dabff7420972b [file] [log] [blame]
Brian Silverman10fb0f32016-03-13 17:05:21 -04001#ifndef AOS_VISION_MATH_VECTOR_H_
2#define AOS_VISION_MATH_VECTOR_H_
3
4#include <cmath>
5
6#include "Eigen/Dense"
7
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -08008namespace aos::vision {
Brian Silverman10fb0f32016-03-13 17:05:21 -04009
10// Represents an n-dimensional vector of doubles with various convenient
11// shortcuts for common operations.
12//
13// This includes overloads of various arithmetic operators for convenience.
14// Multiplication by doubles is scalar multiplication and multiplication by
15// other vectors is element-wise.
16//
17// Accessing elements which don't exist for a given size vector, mixing sizes of
18// vectors in appropriately, etc are compile-time errors.
19template <int size>
20class Vector {
21 public:
Parker Schuh6691f192017-01-14 17:01:02 -080022 Vector() : data_(::Eigen::Matrix<double, 1, size>::Zero()) {}
Brian Silverman10fb0f32016-03-13 17:05:21 -040023
24 Vector(double x, double y) { Set(x, y); }
25
26 Vector(double x, double y, double z) { Set(x, y, z); }
27
28 double Get(int index) const { return data_(index); }
29 void Set(int index, double value) { data_(index) = value; }
30
31 void Set(double x, double y) {
32 static_assert(size == 2, "illegal size");
33 data_(0) = x;
34 data_(1) = y;
35 }
36 void Set(double x, double y, double z) {
37 static_assert(size == 3, "illegal size");
38 data_(0) = x;
39 data_(1) = y;
40 data_(2) = z;
41 }
42 void Set(double x, double y, double z, double w) {
43 static_assert(size == 4, "illegal size");
44 data_(0) = x;
45 data_(1) = y;
46 data_(2) = z;
47 data_(3) = w;
48 }
49
50 double x() const {
51 static_assert(size >= 1, "illegal size");
52 return data_(0);
53 }
54 void x(double xX) {
55 static_assert(size >= 1, "illegal size");
56 data_(0) = xX;
57 }
58
59 double y() const {
60 static_assert(size >= 2, "illegal size");
61 return data_(1);
62 }
63 void y(double yY) {
64 static_assert(size >= 2, "illegal size");
65 data_(1) = yY;
66 }
67
68 double z() const {
69 static_assert(size >= 3, "illegal size");
70 return data_(2);
71 }
72 void z(double zZ) {
73 static_assert(size >= 3, "illegal size");
74 data_(2) = zZ;
75 }
76
77 double w() const {
78 static_assert(size >= 4, "illegal size");
79 return data_(3);
80 }
81 void w(double wW) {
82 static_assert(size >= 4, "illegal size");
83 data_(3) = wW;
84 }
85
86 // Fast part of length.
87 double MagSqr() const { return data_.squaredNorm(); }
88
89 // Length of the vector.
90 double Mag() const { return data_.norm(); }
91
92 // Get underlying data structure
Austin Schuhe6cfbe32019-03-10 18:05:57 -070093 // TODO(austin): Everyone uses column not row vectors.
Brian Silverman10fb0f32016-03-13 17:05:21 -040094 ::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 Schuh6691f192017-01-14 17:01:02 -0800178 double AngleTo(const Vector<size> &other) const {
Brian Silverman10fb0f32016-03-13 17:05:21 -0400179 // 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 Schuh6691f192017-01-14 17:01:02 -0800184 double SquaredDistanceTo(const Vector<size> &other) const {
Brian Silverman10fb0f32016-03-13 17:05:21 -0400185 Vector<size> tmp = *this - other;
186 return tmp.MagSqr();
187 }
188
Parker Schuh02f13f62019-02-16 16:42:41 -0800189 // Returns the distance between this and other.
190 double DistanceTo(const Vector<size> &other) const {
191 return std::sqrt(SquaredDistanceTo(other));
192 }
193
Brian Silverman10fb0f32016-03-13 17:05:21 -0400194 private:
195 // The actual data.
196 ::Eigen::Matrix<double, 1, size> data_;
197};
198
199// Returns the cross product of two points.
200inline double PointsCrossProduct(const Vector<2> &a, const Vector<2> &b) {
201 return a.x() * b.y() - a.y() * b.x();
202}
Parker Schuh02f13f62019-02-16 16:42:41 -0800203
204// Rotates along the z, y, and then x axis (all radians).
205inline Vector<3> Rotate(double rx, double ry, double rz, const Vector<3> vec) {
206 ::Eigen::AngleAxis<double> ax(rx, ::Eigen::Vector3d(1.0, 0.0, 0.0));
207 ::Eigen::AngleAxis<double> ay(ry, ::Eigen::Vector3d(0.0, 1.0, 0.0));
208 ::Eigen::AngleAxis<double> az(rz, ::Eigen::Vector3d(0.0, 0.0, 1.0));
209 Vector<3> result;
210 result.SetData(ax * ay * az * vec.GetData());
211 return result;
212}
213
Parker Schuh6691f192017-01-14 17:01:02 -0800214// scalar multiply
215template <int Size>
216inline Vector<Size> operator*(const double &lhs, Vector<Size> &rhs) {
217 Vector<Size> nv;
218 for (int i = 0; i < Size; i++) {
219 nv.Set(i, lhs * rhs.Get(i));
220 }
221 return nv;
222}
Brian Silverman10fb0f32016-03-13 17:05:21 -0400223
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -0800224} // namespace aos::vision
Brian Silverman10fb0f32016-03-13 17:05:21 -0400225
226#endif // AOS_VISION_MATH_VECTOR_H_