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