blob: 04203e672fe0ba9167915695c78254591c47b320 [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
Stephan Pleinescc500b92024-05-30 10:58:40 -07004#include <algorithm>
Brian Silverman10fb0f32016-03-13 17:05:21 -04005#include <cmath>
Stephan Pleinescc500b92024-05-30 10:58:40 -07006#include <utility>
Brian Silverman10fb0f32016-03-13 17:05:21 -04007
Stephan Pleinescc500b92024-05-30 10:58:40 -07008#include "Eigen/Core"
9#include "Eigen/Geometry"
Brian Silverman10fb0f32016-03-13 17:05:21 -040010
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080011namespace aos::vision {
Brian Silverman10fb0f32016-03-13 17:05:21 -040012
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.
22template <int size>
23class Vector {
24 public:
Parker Schuh6691f192017-01-14 17:01:02 -080025 Vector() : data_(::Eigen::Matrix<double, 1, size>::Zero()) {}
Brian Silverman10fb0f32016-03-13 17:05:21 -040026
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 Schuhe6cfbe32019-03-10 18:05:57 -070096 // TODO(austin): Everyone uses column not row vectors.
Brian Silverman10fb0f32016-03-13 17:05:21 -040097 ::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 Schuh6691f192017-01-14 17:01:02 -0800181 double AngleTo(const Vector<size> &other) const {
Brian Silverman10fb0f32016-03-13 17:05:21 -0400182 // 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 Schuh6691f192017-01-14 17:01:02 -0800187 double SquaredDistanceTo(const Vector<size> &other) const {
Brian Silverman10fb0f32016-03-13 17:05:21 -0400188 Vector<size> tmp = *this - other;
189 return tmp.MagSqr();
190 }
191
Parker Schuh02f13f62019-02-16 16:42:41 -0800192 // Returns the distance between this and other.
193 double DistanceTo(const Vector<size> &other) const {
194 return std::sqrt(SquaredDistanceTo(other));
195 }
196
Brian Silverman10fb0f32016-03-13 17:05:21 -0400197 private:
198 // The actual data.
199 ::Eigen::Matrix<double, 1, size> data_;
200};
201
202// Returns the cross product of two points.
203inline double PointsCrossProduct(const Vector<2> &a, const Vector<2> &b) {
204 return a.x() * b.y() - a.y() * b.x();
205}
Parker Schuh02f13f62019-02-16 16:42:41 -0800206
207// Rotates along the z, y, and then x axis (all radians).
208inline 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 Schuh6691f192017-01-14 17:01:02 -0800217// scalar multiply
218template <int Size>
219inline 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 Silverman10fb0f32016-03-13 17:05:21 -0400226
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -0800227} // namespace aos::vision
Brian Silverman10fb0f32016-03-13 17:05:21 -0400228
229#endif // AOS_VISION_MATH_VECTOR_H_