]> git.tdb.fi Git - libs/math.git/blob - source/linal/vector.h
Require C++11 for building
[libs/math.git] / source / linal / vector.h
1 #ifndef MSP_LINAL_VECTOR_H_
2 #define MSP_LINAL_VECTOR_H_
3
4 #include <algorithm>
5 #include <cmath>
6 #include <ostream>
7
8 namespace Msp {
9 namespace LinAl {
10
11 /**
12 Base class to provide the components of a vector.  This is used so that
13 specializations with individual members can be provided in some dimensions.
14 */
15 template<typename T, unsigned N>
16 class VectorComponents
17 {
18 private:
19         T data[N];
20
21 protected:
22         VectorComponents() { }
23
24 public:
25         T &operator[](unsigned i) { return data[i]; }
26         const T &operator[](unsigned i) const { return data[i]; }
27 };
28
29 template<typename T>
30 class VectorComponents<T, 2>
31 {
32 public:
33         T x, y;
34
35 protected:
36         VectorComponents() { }
37
38 public:
39         T &operator[](unsigned i) { return *(&x+i); }
40         const T &operator[](unsigned i) const { return *(&x+i); }
41 };
42
43 template<typename T>
44 class VectorComponents<T, 3>
45 {
46 public:
47         T x, y, z;
48
49 protected:
50         VectorComponents() { }
51
52 public:
53         T &operator[](unsigned i) { return *(&x+i); }
54         const T &operator[](unsigned i) const { return *(&x+i); }
55 };
56
57 template<typename T>
58 class VectorComponents<T, 4>
59 {
60 public:
61         T x, y, z, w;
62
63 protected:
64         VectorComponents() { }
65
66 public:
67         T &operator[](unsigned i) { return *(&x+i); }
68         const T &operator[](unsigned i) const { return *(&x+i); }
69 };
70
71 /**
72 A general mathematical vector.
73 */
74 template<typename T, unsigned N>
75 class Vector: public VectorComponents<T, N>
76 {
77 public:
78         typedef T ElementType;
79
80         Vector();
81         Vector(const T *);
82
83         /** Constructs a vector from an array of interleaved values.  Intended for
84         use by Matrix row accessor. */
85         Vector(const T *, unsigned);
86
87         template<typename... Args>
88         Vector(T, Args...);
89
90         template<typename U>
91         Vector(const Vector<U, N> &);
92
93         unsigned size() const { return N; }
94
95         template<unsigned M>
96         Vector<T, M> slice(unsigned) const;
97
98         Vector &operator*=(T);
99         Vector &operator/=(T);
100         Vector &operator+=(const Vector &);
101         Vector &operator-=(const Vector &);
102
103         T norm() const;
104         Vector &normalize();
105 };
106
107
108 template<typename T, unsigned N>
109 inline Vector<T, N>::Vector()
110 {
111         for(unsigned i=0; i<N; ++i)
112                 (*this)[i] = T();
113 }
114
115 template<typename T, unsigned N>
116 inline Vector<T, N>::Vector(const T *d)
117 {
118         for(unsigned i=0; i<N; ++i)
119                 (*this)[i] = d[i];
120 }
121
122 template<typename T, unsigned N>
123 inline Vector<T, N>::Vector(const T *d, unsigned stride)
124 {
125         for(unsigned i=0; i<N; ++i)
126                 (*this)[i] = d[i*stride];
127 }
128
129 template<typename T, unsigned N>
130 template<typename... Args>
131 inline Vector<T, N>::Vector(T x_, Args... v)
132 {
133         static_assert(1+sizeof...(v)==N, "Incorrect number of arguments in Vector constructor");
134         (*this)[0] = x_;
135         unsigned i = 1;
136         for(auto c: std::initializer_list<T> { static_cast<T>(v)... })
137                 (*this)[i++] = c;
138 }
139
140 template<typename T, unsigned N>
141 template<typename U>
142 inline Vector<T, N>::Vector(const Vector<U, N> &v)
143 {
144         for(unsigned i=0; i<N; ++i)
145                 (*this)[i] = v[i];
146 }
147
148 template<typename T, unsigned N>
149 inline Vector<T, N+1> compose(const Vector<T, N> &v, T s)
150 {
151         Vector<T, N+1> r;
152         for(unsigned i=0; i<N; ++i)
153                 r[i] = v[i];
154         r[N] = s;
155         return r;
156 }
157
158 template<typename T, unsigned N>
159 inline Vector<T, N+1> compose(T s, const Vector<T, N> &v)
160 {
161         Vector<T, N+1> r;
162         r[0] = s;
163         for(unsigned i=0; i<N; ++i)
164                 r[i+1] = v[i];
165         return r;
166 }
167
168 template<typename T, unsigned N, unsigned M>
169 inline Vector<T, N+M> compose(const Vector<T, N> &v1, const Vector<T, M> &v2)
170 {
171         Vector<T, N+M> r;
172         for(unsigned i=0; i<N; ++i)
173                 r[i] = v1[i];
174         for(unsigned i=0; i<M; ++i)
175                 r[N+i] = v2[i];
176         return r;
177 }
178
179 template<typename T, unsigned N>
180 template<unsigned M>
181 inline Vector<T, M> Vector<T, N>::slice(unsigned j) const
182 {
183         Vector<T, M> r;
184         for(unsigned i=0; i<M; ++i)
185                 r[i] = (*this)[j+i];
186         return r;
187 }
188
189 template<typename T, unsigned N>
190 inline Vector<T, N> &Vector<T, N>::operator*=(T s)
191 {
192         for(unsigned i=0; i<N; ++i)     
193                 (*this)[i] *= s;
194         return *this;
195 }
196
197 template<typename T, unsigned N>
198 inline Vector<T, N> operator*(const Vector<T, N> &v, T s)
199 {
200         Vector<T, N> r(v);
201         return r *= s;
202 }
203
204 template<typename T, unsigned N>
205 inline Vector<T, N> operator*(T s, const Vector<T, N> &v)
206 {
207         return v*s;
208 }
209
210 template<typename T, unsigned N>
211 inline Vector<T, N> &Vector<T, N>::operator/=(T s)
212 {
213         for(unsigned i=0; i<N; ++i)     
214                 (*this)[i] /= s;
215         return *this;
216 }
217
218 template<typename T, unsigned N>
219 inline Vector<T, N> operator/(const Vector<T, N> &v, T s)
220 {
221         Vector<T, N> r(v);
222         return r /= s;
223 }
224
225 template<typename T, unsigned N>
226 inline Vector<T, N> &Vector<T, N>::operator+=(const Vector<T, N> &v)
227 {
228         for(unsigned i=0; i<N; ++i)     
229                 (*this)[i] += v[i];
230         return *this;
231 }
232
233 template<typename T, unsigned N>
234 inline Vector<T, N> operator+(const Vector<T, N> &v1, const Vector<T, N> &v2)
235 {
236         Vector<T, N> r(v1);
237         return r += v2;
238 }
239
240 template<typename T, unsigned N>
241 inline Vector<T, N> &Vector<T, N>::operator-=(const Vector<T, N> &v)
242 {
243         for(unsigned i=0; i<N; ++i)     
244                 (*this)[i] -= v[i];
245         return *this;
246 }
247
248 template<typename T, unsigned N>
249 inline Vector<T, N> operator-(const Vector<T, N> &v1, const Vector<T, N> &v2)
250 {
251         Vector<T, N> r(v1);
252         return r -= v2;
253 }
254
255 template<typename T, unsigned N>
256 inline Vector<T, N> operator-(const Vector<T, N> &v)
257 {
258         Vector<T, N> r(v);
259         for(unsigned i=0; i<N; ++i)
260                 r[i] = -r[i];
261         return r;
262 }
263
264 template<typename T, unsigned N>
265 inline bool operator==(const Vector<T, N> &v, const Vector<T, N> &w)
266 {
267         for(unsigned i=0; i<N; ++i)
268                 if(v[i]!=w[i])
269                         return false;
270         return true;
271 }
272
273 template<typename T, unsigned N>
274 inline T inner_product(const Vector<T, N> &v1, const Vector<T, N> &v2)
275 {
276         T r = T();
277         for(unsigned i=0; i<N; ++i)
278                 r += v1[i]*v2[i];
279         return r;
280 }
281
282 template<typename T, unsigned N>
283 inline T Vector<T, N>::norm() const
284 {
285         using std::sqrt;
286         return sqrt(inner_product(*this, *this));
287 }
288
289 template<typename T, unsigned N>
290 inline Vector<T, N> &Vector<T, N>::normalize()
291 {
292         return *this /= norm();
293 }
294
295 template<typename T, unsigned N>
296 inline Vector<T, N> normalize(const Vector<T, N> &v)
297 {
298         Vector<T, N> r(v);
299         return r.normalize();
300 }
301
302 template<typename T>
303 inline T dot(const Vector<T, 3> &v1, const Vector<T, 3> &v2)
304 {
305         return inner_product(v1, v2);
306 }
307
308 template<typename T>
309 inline Vector<T, 3> cross(const Vector<T, 3> &v1, const Vector<T, 3> &v2)
310 {
311         return Vector<T, 3>(v1.y*v2.z-v1.z*v2.y, v1.z*v2.x-v1.x*v2.z, v1.x*v2.y-v1.y*v2.x);
312 }
313
314 template<typename T, unsigned N>
315 inline std::ostream &operator<<(std::ostream &s, const Vector<T, N> &v)
316 {
317         s << "Vector" << N << '(';
318         for(unsigned i=0; i<N; ++i)
319         {
320                 if(i)
321                         s << ", ";
322                 s << v[i];
323         }
324         s << ')';
325         return s;
326 }
327
328 } // namespace LinAl
329 } // namespace Msp
330
331 #endif