]> git.tdb.fi Git - libs/math.git/blob - source/linal/vector.h
Improve Vector constructor for C++11
[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 #if __cplusplus >= 201103L
88         template<typename... Args>
89         Vector(T, Args...);
90 #else
91         Vector(T, T);
92         Vector(T, T, T);
93         Vector(T, T, T, T);
94 #endif
95         template<typename U>
96         Vector(const Vector<U, N> &);
97
98         unsigned size() const { return N; }
99
100         template<unsigned M>
101         Vector<T, M> slice(unsigned) const;
102
103         Vector &operator*=(T);
104         Vector &operator/=(T);
105         Vector &operator+=(const Vector &);
106         Vector &operator-=(const Vector &);
107
108         T norm() const;
109         Vector &normalize();
110 };
111
112
113 template<typename T, unsigned N>
114 inline Vector<T, N>::Vector()
115 {
116         for(unsigned i=0; i<N; ++i)
117                 (*this)[i] = T();
118 }
119
120 template<typename T, unsigned N>
121 inline Vector<T, N>::Vector(const T *d)
122 {
123         for(unsigned i=0; i<N; ++i)
124                 (*this)[i] = d[i];
125 }
126
127 template<typename T, unsigned N>
128 inline Vector<T, N>::Vector(const T *d, unsigned stride)
129 {
130         for(unsigned i=0; i<N; ++i)
131                 (*this)[i] = d[i*stride];
132 }
133
134 #if __cplusplus >= 201103L
135 template<typename T, unsigned N>
136 template<typename... Args>
137 inline Vector<T, N>::Vector(T x_, Args... v)
138 {
139         static_assert(1+sizeof...(v)==N, "Incorrect number of arguments in Vector constructor");
140         (*this)[0] = x_;
141         unsigned i = 1;
142         for(auto c: std::initializer_list<T> { static_cast<T>(v)... })
143                 (*this)[i++] = c;
144 }
145 #else
146 /* The compiler won't instantiate these unless they are used.  Trying to use
147 them on the wrong class results in an error. */
148 template<typename T, unsigned N>
149 inline Vector<T, N>::Vector(T x_, T y_)
150 {
151         this->VectorComponents<T, 2>::x = x_;
152         this->VectorComponents<T, 2>::y = y_;
153 }
154
155 template<typename T, unsigned N>
156 inline Vector<T, N>::Vector(T x_, T y_, T z_)
157 {
158         this->VectorComponents<T, 3>::x = x_;
159         this->VectorComponents<T, 3>::y = y_;
160         this->VectorComponents<T, 3>::z = z_;
161 }
162
163 template<typename T, unsigned N>
164 inline Vector<T, N>::Vector(T x_, T y_, T z_, T w_)
165 {
166         this->VectorComponents<T, 4>::x = x_;
167         this->VectorComponents<T, 4>::y = y_;
168         this->VectorComponents<T, 4>::z = z_;
169         this->VectorComponents<T, 4>::w = w_;
170 }
171 #endif
172
173 template<typename T, unsigned N>
174 template<typename U>
175 inline Vector<T, N>::Vector(const Vector<U, N> &v)
176 {
177         for(unsigned i=0; i<N; ++i)
178                 (*this)[i] = v[i];
179 }
180
181 template<typename T, unsigned N>
182 inline Vector<T, N+1> compose(const Vector<T, N> &v, T s)
183 {
184         Vector<T, N+1> r;
185         for(unsigned i=0; i<N; ++i)
186                 r[i] = v[i];
187         r[N] = s;
188         return r;
189 }
190
191 template<typename T, unsigned N>
192 inline Vector<T, N+1> compose(T s, const Vector<T, N> &v)
193 {
194         Vector<T, N+1> r;
195         r[0] = s;
196         for(unsigned i=0; i<N; ++i)
197                 r[i+1] = v[i];
198         return r;
199 }
200
201 template<typename T, unsigned N, unsigned M>
202 inline Vector<T, N+M> compose(const Vector<T, N> &v1, const Vector<T, M> &v2)
203 {
204         Vector<T, N+M> r;
205         for(unsigned i=0; i<N; ++i)
206                 r[i] = v1[i];
207         for(unsigned i=0; i<M; ++i)
208                 r[N+i] = v2[i];
209         return r;
210 }
211
212 template<typename T, unsigned N>
213 template<unsigned M>
214 inline Vector<T, M> Vector<T, N>::slice(unsigned j) const
215 {
216         Vector<T, M> r;
217         for(unsigned i=0; i<M; ++i)
218                 r[i] = (*this)[j+i];
219         return r;
220 }
221
222 template<typename T, unsigned N>
223 inline Vector<T, N> &Vector<T, N>::operator*=(T s)
224 {
225         for(unsigned i=0; i<N; ++i)     
226                 (*this)[i] *= s;
227         return *this;
228 }
229
230 template<typename T, unsigned N>
231 inline Vector<T, N> operator*(const Vector<T, N> &v, T s)
232 {
233         Vector<T, N> r(v);
234         return r *= s;
235 }
236
237 template<typename T, unsigned N>
238 inline Vector<T, N> operator*(T s, const Vector<T, N> &v)
239 {
240         return v*s;
241 }
242
243 template<typename T, unsigned N>
244 inline Vector<T, N> &Vector<T, N>::operator/=(T s)
245 {
246         for(unsigned i=0; i<N; ++i)     
247                 (*this)[i] /= s;
248         return *this;
249 }
250
251 template<typename T, unsigned N>
252 inline Vector<T, N> operator/(const Vector<T, N> &v, T s)
253 {
254         Vector<T, N> r(v);
255         return r /= s;
256 }
257
258 template<typename T, unsigned N>
259 inline Vector<T, N> &Vector<T, N>::operator+=(const Vector<T, N> &v)
260 {
261         for(unsigned i=0; i<N; ++i)     
262                 (*this)[i] += v[i];
263         return *this;
264 }
265
266 template<typename T, unsigned N>
267 inline Vector<T, N> operator+(const Vector<T, N> &v1, const Vector<T, N> &v2)
268 {
269         Vector<T, N> r(v1);
270         return r += v2;
271 }
272
273 template<typename T, unsigned N>
274 inline Vector<T, N> &Vector<T, N>::operator-=(const Vector<T, N> &v)
275 {
276         for(unsigned i=0; i<N; ++i)     
277                 (*this)[i] -= v[i];
278         return *this;
279 }
280
281 template<typename T, unsigned N>
282 inline Vector<T, N> operator-(const Vector<T, N> &v1, const Vector<T, N> &v2)
283 {
284         Vector<T, N> r(v1);
285         return r -= v2;
286 }
287
288 template<typename T, unsigned N>
289 inline Vector<T, N> operator-(const Vector<T, N> &v)
290 {
291         Vector<T, N> r(v);
292         for(unsigned i=0; i<N; ++i)
293                 r[i] = -r[i];
294         return r;
295 }
296
297 template<typename T, unsigned N>
298 inline bool operator==(const Vector<T, N> &v, const Vector<T, N> &w)
299 {
300         for(unsigned i=0; i<N; ++i)
301                 if(v[i]!=w[i])
302                         return false;
303         return true;
304 }
305
306 template<typename T, unsigned N>
307 inline T inner_product(const Vector<T, N> &v1, const Vector<T, N> &v2)
308 {
309         T r = T();
310         for(unsigned i=0; i<N; ++i)
311                 r += v1[i]*v2[i];
312         return r;
313 }
314
315 template<typename T, unsigned N>
316 inline T Vector<T, N>::norm() const
317 {
318         using std::sqrt;
319         return sqrt(inner_product(*this, *this));
320 }
321
322 template<typename T, unsigned N>
323 inline Vector<T, N> &Vector<T, N>::normalize()
324 {
325         return *this /= norm();
326 }
327
328 template<typename T, unsigned N>
329 inline Vector<T, N> normalize(const Vector<T, N> &v)
330 {
331         Vector<T, N> r(v);
332         return r.normalize();
333 }
334
335 template<typename T>
336 inline T dot(const Vector<T, 3> &v1, const Vector<T, 3> &v2)
337 {
338         return inner_product(v1, v2);
339 }
340
341 template<typename T>
342 inline Vector<T, 3> cross(const Vector<T, 3> &v1, const Vector<T, 3> &v2)
343 {
344         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);
345 }
346
347 template<typename T, unsigned N>
348 inline std::ostream &operator<<(std::ostream &s, const Vector<T, N> &v)
349 {
350         s << "Vector" << N << '(';
351         for(unsigned i=0; i<N; ++i)
352         {
353                 if(i)
354                         s << ", ";
355                 s << v[i];
356         }
357         s << ')';
358         return s;
359 }
360
361 } // namespace LinAl
362 } // namespace Msp
363
364 #endif