Line data Source code
1 : /*
2 : * Copyright (c) 2006-2016, Visualization and Multimedia Lab,
3 : * University of Zurich <http://vmml.ifi.uzh.ch>,
4 : * Eyescale Software GmbH,
5 : * Blue Brain Project, EPFL
6 : *
7 : * This file is part of VMMLib <https://github.com/VMML/vmmlib/>
8 : *
9 : * Redistribution and use in source and binary forms, with or without
10 : * modification, are permitted provided that the following conditions are met:
11 : *
12 : * Redistributions of source code must retain the above copyright notice, this
13 : * list of conditions and the following disclaimer. Redistributions in binary
14 : * form must reproduce the above copyright notice, this list of conditions and
15 : * the following disclaimer in the documentation and/or other materials provided
16 : * with the distribution. Neither the name of the Visualization and Multimedia
17 : * Lab, University of Zurich nor the names of its contributors may be used to
18 : * endorse or promote products derived from this software without specific prior
19 : * written permission.
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 : * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 : * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 : * POSSIBILITY OF SUCH DAMAGE.
31 : */
32 :
33 : #ifndef __VMML__VECTOR__HPP__
34 : #define __VMML__VECTOR__HPP__
35 :
36 : #include <algorithm>
37 : #include <cmath>
38 : #include <cstring>
39 : #include <iomanip>
40 : #include <iostream>
41 : #include <limits>
42 : #include <stdexcept>
43 : #include <stdint.h>
44 : #include <string>
45 : #include <type_traits>
46 : #include <vector>
47 :
48 : namespace vmml
49 : {
50 : template <size_t M, typename T>
51 : class vector
52 : {
53 : public:
54 : typedef T value_type;
55 : typedef T* iterator;
56 : typedef const T* const_iterator;
57 : typedef std::reverse_iterator<iterator> reverse_iterator;
58 : typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
59 :
60 : static const size_t DIMENSION = M;
61 :
62 : // constructors
63 116 : vector()
64 116 : : array()
65 : {
66 116 : } // http://stackoverflow.com/questions/5602030
67 : explicit vector(const T& a); // sets all components to a;
68 : vector(const T& x, const T& y);
69 : vector(const T& x, const T& y, const T& z);
70 : vector(const T& x, const T& y, const T& z, const T& w);
71 :
72 : #ifndef SWIG
73 : // initializes the first M-1 values from vector_, the last from last_
74 : template <typename TT>
75 : vector(const vector<M - 1, TT>& vector_, T last_,
76 : typename std::enable_if<M == 4, TT>::type* = nullptr);
77 : #endif
78 :
79 : explicit vector(const T* values);
80 :
81 : #ifdef __OSG_MATH
82 : template <typename OSGVEC3>
83 : explicit vector(const OSGVEC3& from,
84 : typename std::enable_if<M == 3, OSGVEC3>::type* = nullptr);
85 : #endif
86 :
87 : // vec< M > with homogeneous coordinates <-> vec< M-1 > conversion ctor
88 : // to-homogenous-coordinates ctor
89 : template <typename TT>
90 : vector(const vector<3, TT>& source_,
91 : typename std::enable_if<M == 4, TT>::type* = nullptr);
92 :
93 : // from-homogenous-coordinates vector
94 : template <typename TT>
95 : vector(const vector<4, TT>& source_,
96 : typename std::enable_if<M == 3, TT>::type* = nullptr);
97 :
98 : template <typename U>
99 : vector(const vector<M, U>& source_);
100 :
101 : // iterators
102 : inline iterator begin();
103 : inline iterator end();
104 : inline const_iterator begin() const;
105 : inline const_iterator end() const;
106 : inline reverse_iterator rbegin();
107 : inline reverse_iterator rend();
108 : inline const_reverse_iterator rbegin() const;
109 : inline const_reverse_iterator rend() const;
110 :
111 : // conversion operators
112 : inline operator T*();
113 : inline operator const T*() const;
114 : // accessors
115 : inline T& operator()(size_t index);
116 : inline const T& operator()(size_t index) const;
117 :
118 : inline T& at(size_t index);
119 : inline const T& at(size_t index) const;
120 :
121 : // element accessors for M <= 4;
122 : inline T& x();
123 : inline T& y();
124 : inline T& z();
125 : inline T& w();
126 : inline const T& x() const;
127 : inline const T& y() const;
128 : inline const T& z() const;
129 : inline const T& w() const;
130 :
131 : // pixel color element accessors for M<= 4
132 : inline T& r();
133 : inline T& g();
134 : inline T& b();
135 : inline T& a();
136 : inline const T& r() const;
137 : inline const T& g() const;
138 : inline const T& b() const;
139 : inline const T& a() const;
140 :
141 : bool operator==(const vector& other) const;
142 : bool operator!=(const vector& other) const;
143 : bool equals(const vector& other,
144 : T tolerance = std::numeric_limits<T>::epsilon()) const;
145 : bool operator<(const vector& other) const;
146 :
147 : // remember kids: c_arrays are dangerous and evil!
148 : T operator=(T filler);
149 :
150 : vector& operator=(const vector& other);
151 :
152 : // returns void to avoid 'silent' loss of precision when chaining
153 : template <typename U>
154 : void operator=(const vector<M, U>& other);
155 :
156 : vector operator*(const vector& other) const;
157 : vector operator/(const vector& other) const;
158 : vector operator+(const vector& other) const;
159 : vector operator-(const vector& other) const;
160 :
161 : void operator*=(const vector& other);
162 : void operator/=(const vector& other);
163 : void operator+=(const vector& other);
164 : void operator-=(const vector& other);
165 :
166 : vector operator*(const T other) const;
167 : vector operator/(const T other) const;
168 : vector operator+(const T other) const;
169 : vector operator-(const T other) const;
170 :
171 : void operator*=(const T other);
172 : void operator/=(const T other);
173 : void operator+=(const T other);
174 : void operator-=(const T other);
175 :
176 : vector operator-() const;
177 :
178 : const vector& negate();
179 :
180 : void set(T a); // sets all components to a;
181 : template <size_t N>
182 : void set(const vector<N, T>& v);
183 :
184 : // sets the first few components to a certain value
185 : void set(T x, T y);
186 : void set(T x, T y, T z);
187 : void set(T x, T y, T z, T w);
188 :
189 : template <typename input_iterator_t>
190 : void iter_set(input_iterator_t begin_, input_iterator_t end_);
191 :
192 : // compute the cross product of two vectors
193 : // note: there's also a free function:
194 : // vector<> cross( const vector<>, const vector<> )
195 : template <typename TT>
196 : vector<M, T>& cross(const vector<M, TT>& b,
197 : typename std::enable_if<M == 3, TT>::type* = nullptr);
198 :
199 : // compute the dot product of two vectors
200 : // note: there's also a free function:
201 : // T dot( const vector<>, const vector<> );
202 : inline T dot(const vector& other) const;
203 :
204 : // normalize the vector
205 : // note: there's also a free function:
206 : // vector<> normalize( const vector<> );
207 : inline T normalize();
208 :
209 : // sets all vector components to random values
210 : // remember to set srand( seed );
211 : // if seed is set to -1, srand( seed ) was set outside set_random
212 : // otherwise srand( seed ) will be called with the given seed
213 : void set_random(int seed = -1);
214 :
215 : inline T length() const;
216 : inline T squared_length() const;
217 :
218 : inline T distance(const vector& other) const;
219 : inline T squared_distance(const vector& other) const;
220 :
221 : /** @return the product of all elements of this vector */
222 : T product() const;
223 :
224 : template <typename TT>
225 : vector<3, T>& rotate(T theta, vector<M, TT> axis,
226 : typename std::enable_if<M == 3, TT>::type* = nullptr);
227 :
228 : /** @return the sub vector of the given length at the given offset. */
229 : template <size_t N, size_t O>
230 : vector<N, T> get_sub_vector(
231 : typename std::enable_if<M >= N + O>::type* = nullptr) const;
232 :
233 : /** Set the sub vector of the given length at the given offset. */
234 : template <size_t N, size_t O>
235 : void set_sub_vector(const vector<N, T>& sub,
236 : typename std::enable_if<M >= N + O>::type* = nullptr);
237 :
238 : // sphere functions - sphere layout: center xyz, radius w
239 : template <typename TT>
240 : inline vector<3, T> project_point_onto_sphere(
241 : const vector<3, TT>& point,
242 : typename std::enable_if<M == 4, TT>::type* = nullptr) const;
243 :
244 : // returns a negative distance if the point lies in the sphere
245 : template <typename TT>
246 : inline T distance_to_sphere(
247 : const vector<3, TT>& point,
248 : typename std::enable_if<M == 4, TT>::type* = nullptr) const;
249 :
250 : // plane functions - plane layout; normal xyz, distance w
251 : template <typename TT>
252 : inline T distance_to_plane(
253 : const vector<3, TT>& point,
254 : typename std::enable_if<M == 4, TT>::type* = nullptr) const;
255 :
256 : template <typename TT>
257 : inline vector<3, T> project_point_onto_plane(
258 : const vector<3, TT>& point,
259 : typename std::enable_if<M == 4, TT>::type* = nullptr) const;
260 :
261 : // returns the index of the minimal resp. maximal value in the vector
262 : size_t find_min_index() const;
263 : size_t find_max_index() const;
264 :
265 : // returns minimal resp. maximal value in the vector
266 : T& find_min();
267 : T& find_max();
268 : const T& find_min() const;
269 : const T& find_max() const;
270 :
271 : void clamp(const T& min = 0.0, const T& max = 1.0);
272 :
273 : inline static size_t size(); // returns M
274 :
275 : bool is_unit_vector() const;
276 :
277 : // perturbs each component by randomly + or - the perturbation parameter
278 : void perturb(T perturbation = 0.0001);
279 :
280 : void sqrt_elementwise();
281 : double norm() const; // l2 norm
282 :
283 : // computes the reciprocal value for each component, x = 1/x;
284 : // WARNING: might result in nans if division by 0!
285 : void reciprocal();
286 : // computes the reciprocal value for each component, x = 1/x;
287 : // checks every component for 0, sets to max value if zero.
288 : void reciprocal_safe();
289 :
290 : template <typename TT>
291 : void cast_from(const vector<M, TT>& other);
292 :
293 : size_t nnz() const;
294 :
295 1 : friend std::ostream& operator<<(std::ostream& os, const vector& vector_)
296 : {
297 1 : os << "[ ";
298 5 : for (size_t index = 0; index < M; ++index)
299 4 : os << vector_.at(index) << " ";
300 1 : return os << "]";
301 : }
302 :
303 : /** @name Convenience presets for 3 and 4 component vectors */
304 : //@{
305 : static vector<M, T> zero();
306 : static vector<M, T> forward();
307 : static vector<M, T> backward();
308 : static vector<M, T> up();
309 : static vector<M, T> down();
310 : static vector<M, T> left();
311 : static vector<M, T> right();
312 : static vector<M, T> unitX();
313 : static vector<M, T> unitY();
314 : static vector<M, T> unitZ();
315 : //@}
316 :
317 : T array[M]; //!< storage
318 : };
319 :
320 : //
321 : // some free functions for convenience
322 : //
323 :
324 : template <size_t M, typename T>
325 : bool equals(const vector<M, T>& a, const vector<M, T>& b)
326 : {
327 : return a.equals(b);
328 : }
329 :
330 : // allows float * vector, not only vector * float
331 : template <size_t M, typename T>
332 1 : static vector<M, T> operator*(T factor, const vector<M, T>& vector_)
333 : {
334 1 : return vector_ * factor;
335 : }
336 :
337 : template <size_t M, typename T>
338 3 : inline T dot(const vector<M, T>& first, const vector<M, T>& second)
339 : {
340 3 : return first.dot(second);
341 : }
342 :
343 : template <size_t M, typename T>
344 10 : inline vector<M, T> cross(vector<M, T> a, const vector<M, T>& b)
345 : {
346 10 : return a.cross(b);
347 : }
348 :
349 : template <size_t M, typename T>
350 1 : vector<M, T> compute_normal(const vector<M, T>& a, const vector<M, T>& b,
351 : const vector<M, T>& c)
352 : {
353 : // right hand system, CCW triangle
354 1 : const vector<M, T> u = b - a;
355 1 : const vector<M, T> v = c - a;
356 1 : vector<M, T> w = cross(u, v);
357 1 : w.normalize();
358 1 : return w;
359 : }
360 :
361 : template <typename T>
362 2 : vector<3, T> rotate(vector<3, T> vec, const T theta, const vector<3, T>& axis)
363 : {
364 2 : return vec.rotate(theta, axis);
365 : }
366 :
367 : template <size_t M, typename T>
368 2 : inline vector<M, T> normalize(vector<M, T> vector_)
369 : {
370 2 : vector_.normalize();
371 2 : return vector_;
372 : }
373 :
374 : template <typename T>
375 6 : inline vector<4, T> compute_plane(const vector<3, T>& a, const vector<3, T>& b,
376 : const vector<3, T>& c)
377 : {
378 6 : const vector<3, T> cb = b - c;
379 6 : const vector<3, T> ba = a - b;
380 :
381 6 : vector<4, T> plane = vector<4, T>(cross(cb, ba));
382 6 : plane.normalize();
383 6 : plane.w() = -plane.x() * a.x() - plane.y() * a.y() - plane.z() * a.z();
384 6 : return plane;
385 : }
386 :
387 : template <size_t M, typename T>
388 7 : vector<M, T>::vector(const T& _a)
389 : {
390 29 : for (iterator it = begin(), it_end = end(); it != it_end; ++it)
391 : {
392 22 : *it = _a;
393 : }
394 7 : }
395 :
396 : template <size_t M, typename T>
397 1 : vector<M, T>::vector(const T& _x, const T& _y)
398 : {
399 1 : array[0] = _x;
400 1 : array[1] = _y;
401 1 : }
402 :
403 : template <size_t M, typename T>
404 74 : vector<M, T>::vector(const T& _x, const T& _y, const T& _z)
405 : {
406 74 : array[0] = _x;
407 74 : array[1] = _y;
408 74 : array[2] = _z;
409 74 : }
410 :
411 : template <size_t M, typename T>
412 26 : vector<M, T>::vector(const T& _x, const T& _y, const T& _z, const T& _w)
413 : {
414 26 : array[0] = _x;
415 26 : array[1] = _y;
416 26 : array[2] = _z;
417 26 : array[3] = _w;
418 26 : }
419 :
420 : template <size_t M, typename T>
421 26 : vector<M, T>::vector(const T* values)
422 : {
423 26 : memcpy(array, values, M * sizeof(T));
424 26 : }
425 :
426 : #ifdef __OSG_MATH
427 : template <size_t M, typename T>
428 : template <typename OSGVEC3>
429 : vector<M, T>::vector(const OSGVEC3& from,
430 : typename std::enable_if<M == 3, OSGVEC3>::type*)
431 : {
432 : array[0] = from.x();
433 : array[1] = from.y();
434 : array[2] = from.z();
435 : }
436 : #endif
437 :
438 : #ifndef SWIG
439 : template <size_t M, typename T>
440 : template <typename TT>
441 : // initializes the first M-1 values from vector_, the last from last_
442 1 : vector<M, T>::vector(const vector<M - 1, TT>& vector_, T last_,
443 : typename std::enable_if<M == 4, TT>::type*)
444 : {
445 1 : array[0] = vector_.array[0];
446 1 : array[1] = vector_.array[1];
447 1 : array[2] = vector_.array[2];
448 1 : array[3] = last_;
449 1 : }
450 : #endif
451 :
452 : // to-homogenous-coordinates ctor
453 : template <size_t M, typename T>
454 : template <typename TT>
455 47 : vector<M, T>::vector(const vector<3, TT>& source_,
456 : typename std::enable_if<M == 4, TT>::type*)
457 : {
458 47 : std::copy(source_.begin(), source_.end(), begin());
459 47 : at(M - 1) = static_cast<T>(1.0);
460 47 : }
461 :
462 : // from-homogenous-coordinates ctor
463 : template <size_t M, typename T>
464 : template <typename TT>
465 2 : vector<M, T>::vector(const vector<4, TT>& source_,
466 : typename std::enable_if<M == 3, TT>::type*)
467 : {
468 2 : const T w_reci = static_cast<T>(1.0) / source_(M);
469 2 : iterator it = begin(), it_end = end();
470 8 : for (size_t index = 0; it != it_end; ++it, ++index)
471 6 : *it = source_(index) * w_reci;
472 2 : }
473 :
474 : template <size_t M, typename T>
475 : template <typename U>
476 1 : vector<M, T>::vector(const vector<M, U>& source_)
477 : {
478 1 : (*this) = source_;
479 1 : }
480 :
481 : namespace
482 : {
483 : template <size_t M, typename T>
484 8 : vector<M, T> _createVector(const T x, const T y, const T z,
485 : typename std::enable_if<M == 3>::type* = nullptr)
486 : {
487 8 : return vector<M, T>(x, y, z);
488 : }
489 :
490 : template <size_t M, typename T>
491 1 : vector<M, T> _createVector(const T x, const T y, const T z,
492 : typename std::enable_if<M == 4>::type* = nullptr)
493 : {
494 1 : return vector<M, T>(x, y, z, 1);
495 : }
496 : }
497 :
498 : template <size_t M, typename T>
499 1 : vector<M, T> vector<M, T>::zero()
500 : {
501 1 : return _createVector<M, T>(0, 0, 0);
502 : }
503 :
504 : template <size_t M, typename T>
505 3 : vector<M, T> vector<M, T>::forward()
506 : {
507 3 : return _createVector<M, T>(0, 0, -1);
508 : }
509 :
510 : template <size_t M, typename T>
511 1 : vector<M, T> vector<M, T>::backward()
512 : {
513 1 : return _createVector<M, T>(0, 0, 1);
514 : }
515 :
516 : template <size_t M, typename T>
517 2 : vector<M, T> vector<M, T>::up()
518 : {
519 2 : return _createVector<M, T>(0, 1, 0);
520 : }
521 :
522 : template <size_t M, typename T>
523 : vector<M, T> vector<M, T>::down()
524 : {
525 : return _createVector<M, T>(0, -1, 0);
526 : }
527 :
528 : template <size_t M, typename T>
529 2 : vector<M, T> vector<M, T>::left()
530 : {
531 2 : return _createVector<M, T>(-1, 0, 0);
532 : }
533 :
534 : template <size_t M, typename T>
535 : vector<M, T> vector<M, T>::right()
536 : {
537 : return _createVector<M, T>(1, 0, 0);
538 : }
539 :
540 : template <size_t M, typename T>
541 : vector<M, T> vector<M, T>::unitX()
542 : {
543 : return _createVector<M, T>(1, 0, 0);
544 : }
545 :
546 : template <size_t M, typename T>
547 : vector<M, T> vector<M, T>::unitY()
548 : {
549 : return _createVector<M, T>(0, 1, 0);
550 : }
551 :
552 : template <size_t M, typename T>
553 : vector<M, T> vector<M, T>::unitZ()
554 : {
555 : return _createVector<M, T>(0, 0, 1);
556 : }
557 :
558 : template <size_t M, typename T>
559 1 : void vector<M, T>::set(T _a)
560 : {
561 5 : for (iterator it = begin(), it_end = end(); it != it_end; ++it)
562 4 : *it = _a;
563 1 : }
564 :
565 : template <size_t M, typename T>
566 : template <size_t N>
567 : void vector<M, T>::set(const vector<N, T>& v)
568 : {
569 : size_t minimum = M;
570 : if (N < M)
571 : minimum = N;
572 : memcpy(array, v.array, sizeof(T) * minimum);
573 : }
574 :
575 : template <size_t M, typename T>
576 : void vector<M, T>::set(T _x, T _y)
577 : {
578 : array[0] = _x;
579 : array[1] = _y;
580 : }
581 :
582 : template <size_t M, typename T>
583 : void vector<M, T>::set(T _x, T _y, T _z)
584 : {
585 : array[0] = _x;
586 : array[1] = _y;
587 : array[2] = _z;
588 : }
589 :
590 : template <size_t M, typename T>
591 1 : void vector<M, T>::set(T _x, T _y, T _z, T _w)
592 : {
593 1 : array[0] = _x;
594 1 : array[1] = _y;
595 1 : array[2] = _z;
596 1 : array[3] = _w;
597 1 : }
598 :
599 : template <size_t M, typename T>
600 26 : inline T& vector<M, T>::operator()(size_t index)
601 : {
602 26 : return at(index);
603 : }
604 :
605 : template <size_t M, typename T>
606 48 : inline const T& vector<M, T>::operator()(size_t index) const
607 : {
608 48 : return at(index);
609 : }
610 :
611 : template <size_t M, typename T>
612 527 : inline T& vector<M, T>::at(size_t index)
613 : {
614 527 : if (index >= M)
615 0 : throw std::runtime_error("at() - index out of bounds");
616 527 : return array[index];
617 : }
618 :
619 : template <size_t M, typename T>
620 869 : inline const T& vector<M, T>::at(size_t index) const
621 : {
622 869 : if (index >= M)
623 0 : throw std::runtime_error("at() - index out of bounds");
624 869 : return array[index];
625 : }
626 :
627 : template <size_t M, typename T>
628 0 : vector<M, T>::operator T*()
629 : {
630 0 : return array;
631 : }
632 :
633 : template <size_t M, typename T>
634 111 : vector<M, T>::operator const T*() const
635 : {
636 111 : return array;
637 : }
638 :
639 : template <size_t M, typename T>
640 1 : vector<M, T> vector<M, T>::operator*(const vector<M, T>& other) const
641 : {
642 1 : vector<M, T> result;
643 5 : for (size_t index = 0; index < M; ++index)
644 4 : result.at(index) = at(index) * other.at(index);
645 1 : return result;
646 : }
647 :
648 : template <size_t M, typename T>
649 1 : vector<M, T> vector<M, T>::operator/(const vector<M, T>& other) const
650 : {
651 1 : vector<M, T> result;
652 5 : for (size_t index = 0; index < M; ++index)
653 4 : result.at(index) = at(index) / other.at(index);
654 1 : return result;
655 : }
656 :
657 : template <size_t M, typename T>
658 19 : vector<M, T> vector<M, T>::operator+(const vector<M, T>& other) const
659 : {
660 19 : vector<M, T> result;
661 80 : for (size_t index = 0; index < M; ++index)
662 61 : result.at(index) = at(index) + other.at(index);
663 19 : return result;
664 : }
665 :
666 : template <size_t M, typename T>
667 34 : vector<M, T> vector<M, T>::operator-(const vector<M, T>& other) const
668 : {
669 34 : vector<M, T> result;
670 140 : for (size_t index = 0; index < M; ++index)
671 106 : result.at(index) = at(index) - other.at(index);
672 34 : return result;
673 : }
674 :
675 : template <size_t M, typename T>
676 1 : void vector<M, T>::operator*=(const vector<M, T>& other)
677 : {
678 5 : for (size_t index = 0; index < M; ++index)
679 4 : at(index) *= other.at(index);
680 1 : }
681 :
682 : template <size_t M, typename T>
683 1 : void vector<M, T>::operator/=(const vector<M, T>& other)
684 : {
685 5 : for (size_t index = 0; index < M; ++index)
686 4 : at(index) /= other.at(index);
687 1 : }
688 :
689 : template <size_t M, typename T>
690 1 : void vector<M, T>::operator+=(const vector<M, T>& other)
691 : {
692 5 : for (size_t index = 0; index < M; ++index)
693 4 : at(index) += other.at(index);
694 1 : }
695 :
696 : template <size_t M, typename T>
697 1 : void vector<M, T>::operator-=(const vector<M, T>& other)
698 : {
699 5 : for (size_t index = 0; index < M; ++index)
700 4 : at(index) -= other.at(index);
701 1 : }
702 :
703 : template <size_t M, typename T>
704 27 : vector<M, T> vector<M, T>::operator*(const T other) const
705 : {
706 27 : vector<M, T> result;
707 110 : for (size_t index = 0; index < M; ++index)
708 83 : result.at(index) = at(index) * other;
709 27 : return result;
710 : }
711 :
712 : template <size_t M, typename T>
713 1 : vector<M, T> vector<M, T>::operator/(const T other) const
714 : {
715 1 : vector<M, T> result;
716 5 : for (size_t index = 0; index < M; ++index)
717 4 : result.at(index) = at(index) / other;
718 1 : return result;
719 : }
720 :
721 : template <size_t M, typename T>
722 1 : vector<M, T> vector<M, T>::operator+(const T other) const
723 : {
724 1 : vector<M, T> result;
725 5 : for (size_t index = 0; index < M; ++index)
726 4 : result.at(index) = at(index) + other;
727 1 : return result;
728 : }
729 :
730 : template <size_t M, typename T>
731 1 : vector<M, T> vector<M, T>::operator-(const T other) const
732 : {
733 1 : vector<M, T> result;
734 5 : for (size_t index = 0; index < M; ++index)
735 4 : result.at(index) = at(index) - other;
736 1 : return result;
737 : }
738 :
739 : template <size_t M, typename T>
740 20 : void vector<M, T>::operator*=(const T other)
741 : {
742 88 : for (size_t index = 0; index < M; ++index)
743 68 : at(index) *= other;
744 20 : }
745 :
746 : template <size_t M, typename T>
747 1 : void vector<M, T>::operator/=(const T other)
748 : {
749 5 : for (size_t index = 0; index < M; ++index)
750 4 : at(index) /= other;
751 1 : }
752 :
753 : template <size_t M, typename T>
754 1 : void vector<M, T>::operator+=(const T other)
755 : {
756 5 : for (size_t index = 0; index < M; ++index)
757 4 : at(index) += other;
758 1 : }
759 :
760 : template <size_t M, typename T>
761 1 : void vector<M, T>::operator-=(const T other)
762 : {
763 5 : for (size_t index = 0; index < M; ++index)
764 4 : at(index) -= other;
765 1 : }
766 :
767 : template <size_t M, typename T>
768 2 : vector<M, T> vector<M, T>::operator-() const
769 : {
770 2 : vector<M, T> v(*this);
771 2 : return v.negate();
772 : }
773 :
774 : template <size_t M, typename T>
775 2 : const vector<M, T>& vector<M, T>::negate()
776 : {
777 8 : for (size_t index = 0; index < M; ++index)
778 6 : array[index] = -array[index];
779 2 : return *this;
780 : }
781 :
782 : template <size_t M, typename T>
783 98 : inline T& vector<M, T>::x()
784 : {
785 98 : return array[0];
786 : }
787 :
788 : template <size_t M, typename T>
789 99 : inline T& vector<M, T>::y()
790 : {
791 99 : return array[1];
792 : }
793 :
794 : template <size_t M, typename T>
795 94 : inline T& vector<M, T>::z()
796 : {
797 94 : return array[2];
798 : }
799 :
800 : template <size_t M, typename T>
801 13 : inline T& vector<M, T>::w()
802 : {
803 13 : return array[3];
804 : }
805 :
806 : template <size_t M, typename T>
807 199 : inline const T& vector<M, T>::x() const
808 : {
809 199 : return array[0];
810 : }
811 :
812 : template <size_t M, typename T>
813 193 : inline const T& vector<M, T>::y() const
814 : {
815 193 : return array[1];
816 : }
817 :
818 : template <size_t M, typename T>
819 191 : inline const T& vector<M, T>::z() const
820 : {
821 191 : return array[2];
822 : }
823 :
824 : template <size_t M, typename T>
825 100 : inline const T& vector<M, T>::w() const
826 : {
827 100 : return array[3];
828 : }
829 :
830 : template <size_t M, typename T>
831 : inline T& vector<M, T>::r()
832 : {
833 : return array[0];
834 : }
835 :
836 : template <size_t M, typename T>
837 : inline T& vector<M, T>::g()
838 : {
839 : return array[1];
840 : }
841 :
842 : template <size_t M, typename T>
843 : inline T& vector<M, T>::b()
844 : {
845 : return array[2];
846 : }
847 :
848 : template <size_t M, typename T>
849 : inline T& vector<M, T>::a()
850 : {
851 : return array[3];
852 : }
853 :
854 : template <size_t M, typename T>
855 : inline const T& vector<M, T>::r() const
856 : {
857 : return array[0];
858 : }
859 :
860 : template <size_t M, typename T>
861 : inline const T& vector<M, T>::g() const
862 : {
863 : return array[1];
864 : }
865 :
866 : template <size_t M, typename T>
867 : inline const T& vector<M, T>::b() const
868 : {
869 : return array[2];
870 : }
871 :
872 : template <size_t M, typename T>
873 : inline const T& vector<M, T>::a() const
874 : {
875 : return array[3];
876 : }
877 :
878 : template <size_t M, typename T>
879 : template <typename TT>
880 11 : vector<M, T>& vector<M, T>::cross(const vector<M, TT>& rhs,
881 : typename std::enable_if<M == 3, TT>::type*)
882 : {
883 11 : const T x_ = y() * rhs.z() - z() * rhs.y();
884 11 : const T y_ = z() * rhs.x() - x() * rhs.z();
885 11 : const T z_ = x() * rhs.y() - y() * rhs.x();
886 11 : x() = x_;
887 11 : y() = y_;
888 11 : z() = z_;
889 11 : return *this;
890 : }
891 :
892 : template <size_t M, typename T>
893 44 : inline T vector<M, T>::dot(const vector<M, T>& other) const
894 : {
895 44 : T tmp = 0.0;
896 216 : for (size_t index = 0; index < M; ++index)
897 172 : tmp += at(index) * other.at(index);
898 :
899 44 : return tmp;
900 : }
901 :
902 : template <size_t M, typename T>
903 19 : inline T vector<M, T>::normalize()
904 : {
905 19 : const T len = length();
906 19 : if (len <= std::numeric_limits<T>::epsilon())
907 0 : return 0;
908 :
909 19 : const T tmp = 1.0 / len;
910 19 : (*this) *= tmp;
911 19 : return len;
912 : }
913 :
914 : template <size_t M, typename T>
915 27 : inline T vector<M, T>::length() const
916 : {
917 27 : return std::sqrt(squared_length());
918 : }
919 :
920 : template <size_t M, typename T>
921 28 : inline T vector<M, T>::squared_length() const
922 : {
923 28 : T _squared_length = 0.0;
924 122 : for (const_iterator it = begin(), it_end = end(); it != it_end; ++it)
925 94 : _squared_length += (*it) * (*it);
926 :
927 28 : return _squared_length;
928 : }
929 :
930 : template <size_t M, typename T>
931 : inline T vector<M, T>::distance(const vector<M, T>& other) const
932 : {
933 : return std::sqrt(squared_distance(other));
934 : }
935 :
936 : template <size_t M, typename T>
937 : inline T vector<M, T>::squared_distance(const vector<M, T>& other) const
938 : {
939 : vector<M, T> tmp(*this);
940 : tmp -= other;
941 : return tmp.squared_length();
942 : }
943 :
944 : template <size_t M, typename T>
945 2 : inline T vector<M, T>::product() const
946 : {
947 2 : T result = at(0);
948 6 : for (size_t i = 1; i < M; ++i)
949 4 : result *= at(i);
950 2 : return result;
951 : }
952 :
953 : template <size_t M, typename T>
954 : template <typename TT>
955 3 : vector<3, T>& vector<M, T>::rotate(const T theta, vector<M, TT> axis,
956 : typename std::enable_if<M == 3, TT>::type*)
957 : {
958 3 : const T costheta = std::cos(theta);
959 3 : const T sintheta = std::sin(theta);
960 :
961 3 : axis.normalize();
962 6 : return *this = vector<3, T>(
963 6 : (costheta + (1 - costheta) * axis.x() * axis.x()) * x() +
964 6 : ((1 - costheta) * axis.x() * axis.y() -
965 6 : axis.z() * sintheta) *
966 9 : y() +
967 6 : ((1 - costheta) * axis.x() * axis.z() +
968 6 : axis.y() * sintheta) *
969 3 : z(),
970 :
971 6 : ((1 - costheta) * axis.x() * axis.y() + axis.z() * sintheta) *
972 6 : x() +
973 9 : (costheta + (1 - costheta) * axis.y() * axis.y()) * y() +
974 6 : ((1 - costheta) * axis.y() * axis.z() -
975 6 : axis.x() * sintheta) *
976 3 : z(),
977 :
978 6 : ((1 - costheta) * axis.x() * axis.z() - axis.y() * sintheta) *
979 6 : x() +
980 6 : ((1 - costheta) * axis.y() * axis.z() +
981 6 : axis.x() * sintheta) *
982 9 : y() +
983 9 : (costheta + (1 - costheta) * axis.z() * axis.z()) * z());
984 : }
985 :
986 : // sphere layout: center xyz, radius w
987 : template <size_t M, typename T>
988 : template <typename TT>
989 : inline vector<3, T> vector<M, T>::project_point_onto_sphere(
990 : const vector<3, TT>& point,
991 : typename std::enable_if<M == 4, TT>::type*) const
992 : {
993 : const vector<3, T>& center_ = get_sub_vector<3>();
994 :
995 : vector<3, T> projected_point(point);
996 : projected_point -= center_;
997 : projected_point.normalize();
998 : projected_point *= w();
999 : return center_ + projected_point;
1000 : }
1001 :
1002 : // sphere layout: center xyz, radius w
1003 : template <size_t M, typename T>
1004 : template <typename TT>
1005 : inline T vector<M, T>::distance_to_sphere(
1006 : const vector<3, TT>& point,
1007 : typename std::enable_if<M == 4, TT>::type*) const
1008 : {
1009 : const vector<3, T>& center_ = get_sub_vector<3>();
1010 : return (point - center_).length() - w();
1011 : }
1012 :
1013 : template <size_t M, typename T>
1014 : template <size_t N, size_t O>
1015 7 : vector<N, T> vector<M, T>::get_sub_vector(
1016 : typename std::enable_if<M >= N + O>::type*) const
1017 : {
1018 7 : return vector<N, T>(array + O);
1019 : }
1020 :
1021 : template <size_t M, typename T>
1022 : template <size_t N, size_t O>
1023 1 : void vector<M, T>::set_sub_vector(const vector<N, T>& sub,
1024 : typename std::enable_if<M >= N + O>::type*)
1025 : {
1026 1 : ::memcpy(array + O, sub.array, N * sizeof(T));
1027 1 : }
1028 :
1029 : // plane: normal xyz, distance w
1030 : template <size_t M, typename T>
1031 : template <typename TT>
1032 : inline T vector<M, T>::distance_to_plane(
1033 : const vector<3, TT>& point,
1034 : typename std::enable_if<M == 4, TT>::type*) const
1035 : {
1036 : const vector<3, T>& normal = get_sub_vector<3>();
1037 : return normal.dot(point) + w();
1038 : }
1039 :
1040 : // plane: normal xyz, distance w
1041 : template <size_t M, typename T>
1042 : template <typename TT>
1043 : vector<3, T> vector<M, T>::project_point_onto_plane(
1044 : const vector<3, TT>& point,
1045 : typename std::enable_if<M == 4, TT>::type*) const
1046 : {
1047 : const vector<3, T>& normal = get_sub_vector<3>();
1048 : return point - (normal * distance_to_plane(point));
1049 : }
1050 :
1051 : template <size_t M, typename T>
1052 30 : bool vector<M, T>::operator==(const vector<M, T>& other) const
1053 : {
1054 30 : return memcmp(array, other.array, sizeof(array)) == 0;
1055 : }
1056 :
1057 : template <size_t M, typename T>
1058 : bool vector<M, T>::operator!=(const vector<M, T>& other) const
1059 : {
1060 : return !this->operator==(other);
1061 : }
1062 :
1063 : template <size_t M, typename T>
1064 2 : bool vector<M, T>::equals(const vector<M, T>& other, T tolerance) const
1065 : {
1066 8 : for (size_t index = 0; index < M; ++index)
1067 6 : if (fabs(at(index) - other(index)) >= tolerance)
1068 0 : return false;
1069 2 : return true;
1070 : }
1071 :
1072 : template <size_t M, typename T>
1073 : bool vector<M, T>::operator<(const vector<M, T>& other) const
1074 : {
1075 : for (size_t index = 0; index < M; ++index)
1076 : {
1077 : if (at(index) < other.at(index))
1078 : return true;
1079 : if (other.at(index) < at(index))
1080 : return false;
1081 : }
1082 : return false;
1083 : }
1084 :
1085 : template <size_t M, typename T>
1086 : T vector<M, T>::operator=(T filler_value)
1087 : {
1088 : for (size_t index = 0; index < M; ++index)
1089 : at(index) = filler_value;
1090 : return filler_value;
1091 : }
1092 :
1093 : template <size_t M, typename T>
1094 40 : vector<M, T>& vector<M, T>::operator=(const vector<M, T>& other)
1095 : {
1096 40 : if (this != &other)
1097 40 : memcpy(array, other.array, M * sizeof(T));
1098 40 : return *this;
1099 : }
1100 :
1101 : // returns void to avoid 'silent' loss of precision when chaining
1102 : template <size_t M, typename T>
1103 : template <typename U>
1104 2 : void vector<M, T>::operator=(const vector<M, U>& source_)
1105 : {
1106 : typedef typename vector<M, U>::const_iterator u_c_iter;
1107 2 : u_c_iter it = source_.begin(), it_end = source_.end();
1108 8 : for (iterator my_it = begin(); it != it_end; ++it, ++my_it)
1109 6 : *my_it = static_cast<T>(*it);
1110 2 : }
1111 :
1112 : template <size_t M, typename T>
1113 : template <typename input_iterator_t>
1114 4 : void vector<M, T>::iter_set(input_iterator_t begin_, input_iterator_t end_)
1115 : {
1116 4 : input_iterator_t in_it = begin_;
1117 4 : iterator it = begin(), it_end = end();
1118 34 : for (; it != it_end && in_it != end_; ++it, ++in_it)
1119 15 : (*it) = static_cast<T>(*in_it);
1120 4 : }
1121 :
1122 : template <size_t M, typename T>
1123 : void vector<M, T>::clamp(const T& min, const T& max)
1124 : {
1125 : for (size_t i = 0; i < M; ++i)
1126 : {
1127 : if (array[i] < min)
1128 : array[i] = min;
1129 : if (array[i] > max)
1130 : array[i] = max;
1131 : }
1132 : }
1133 :
1134 : template <size_t M, typename T>
1135 : inline size_t vector<M, T>::size()
1136 : {
1137 : return M;
1138 : }
1139 :
1140 : template <size_t M, typename T>
1141 2 : size_t vector<M, T>::find_min_index() const
1142 : {
1143 2 : return std::min_element(begin(), end()) - begin();
1144 : }
1145 :
1146 : template <size_t M, typename T>
1147 2 : size_t vector<M, T>::find_max_index() const
1148 : {
1149 2 : return std::max_element(begin(), end()) - begin();
1150 : }
1151 :
1152 : template <size_t M, typename T>
1153 2 : T& vector<M, T>::find_min()
1154 : {
1155 2 : return *std::min_element(begin(), end());
1156 : }
1157 :
1158 : template <size_t M, typename T>
1159 : const T& vector<M, T>::find_min() const
1160 : {
1161 : return *std::min_element(begin(), end());
1162 : }
1163 :
1164 : template <size_t M, typename T>
1165 2 : T& vector<M, T>::find_max()
1166 : {
1167 2 : return *std::max_element(begin(), end());
1168 : }
1169 :
1170 : template <size_t M, typename T>
1171 : const T& vector<M, T>::find_max() const
1172 : {
1173 : return *std::max_element(begin(), end());
1174 : }
1175 :
1176 : template <size_t M, typename T>
1177 71 : inline typename vector<M, T>::iterator vector<M, T>::begin()
1178 : {
1179 71 : return array;
1180 : }
1181 :
1182 : template <size_t M, typename T>
1183 21 : inline typename vector<M, T>::iterator vector<M, T>::end()
1184 : {
1185 21 : return array + M;
1186 : ;
1187 : }
1188 :
1189 : template <size_t M, typename T>
1190 86 : inline typename vector<M, T>::const_iterator vector<M, T>::begin() const
1191 : {
1192 86 : return array;
1193 : }
1194 :
1195 : template <size_t M, typename T>
1196 82 : inline typename vector<M, T>::const_iterator vector<M, T>::end() const
1197 : {
1198 82 : return array + M;
1199 : ;
1200 : }
1201 :
1202 : template <size_t M, typename T>
1203 : inline typename vector<M, T>::reverse_iterator vector<M, T>::rbegin()
1204 : {
1205 : return array + M - 1;
1206 : }
1207 :
1208 : template <size_t M, typename T>
1209 : inline typename vector<M, T>::reverse_iterator vector<M, T>::rend()
1210 : {
1211 : return array - 1;
1212 : }
1213 :
1214 : template <size_t M, typename T>
1215 : inline typename vector<M, T>::const_reverse_iterator vector<M, T>::rbegin()
1216 : const
1217 : {
1218 : return array + M - 1;
1219 : }
1220 :
1221 : template <size_t M, typename T>
1222 : inline typename vector<M, T>::const_reverse_iterator vector<M, T>::rend() const
1223 : {
1224 : return array - 1;
1225 : }
1226 :
1227 : template <size_t M, typename T>
1228 : bool vector<M, T>::is_unit_vector() const
1229 : {
1230 : const_iterator it = begin(), it_end = end();
1231 : bool one = false;
1232 : for (; it != it_end; ++it)
1233 : {
1234 : if (*it == 1.0)
1235 : {
1236 : if (one)
1237 : return false;
1238 : one = true;
1239 : }
1240 : else if (*it != 0.0)
1241 : {
1242 : return false;
1243 : }
1244 : }
1245 : return one;
1246 : }
1247 :
1248 : template <size_t M, typename T>
1249 : void vector<M, T>::perturb(T perturbation)
1250 : {
1251 : for (iterator it = begin(), it_end = end(); it != it_end; ++it)
1252 : {
1253 : (*it) += (rand() & 1u) ? perturbation : -perturbation;
1254 : }
1255 : }
1256 :
1257 : template <size_t M, typename T>
1258 1 : void vector<M, T>::sqrt_elementwise()
1259 : {
1260 5 : for (iterator it = begin(), it_end = end(); it != it_end; ++it)
1261 : {
1262 4 : (*it) = std::sqrt(*it);
1263 : }
1264 1 : }
1265 :
1266 : template <size_t M, typename T>
1267 1 : void vector<M, T>::reciprocal()
1268 : {
1269 5 : for (iterator it = begin(), it_end = end(); it != it_end; ++it)
1270 4 : (*it) = static_cast<T>(1) / (*it);
1271 1 : }
1272 :
1273 : template <size_t M, typename T>
1274 : void vector<M, T>::reciprocal_safe()
1275 : {
1276 : for (iterator it = begin(), it_end = end(); it != it_end; ++it)
1277 : {
1278 : T& v = *it;
1279 :
1280 : if (v == 0)
1281 : v = std::numeric_limits<T>::max();
1282 : else
1283 : v = static_cast<T>(1) / v;
1284 : }
1285 : }
1286 :
1287 : template <size_t M, typename T>
1288 : template <typename TT>
1289 : void vector<M, T>::cast_from(const vector<M, TT>& other)
1290 : {
1291 : typedef vmml::vector<M, TT> vector_tt_type;
1292 : typedef typename vector_tt_type::const_iterator tt_const_iterator;
1293 :
1294 : iterator it = begin(), it_end = end();
1295 : tt_const_iterator other_it = other.begin();
1296 : for (; it != it_end; ++it, ++other_it)
1297 : {
1298 : *it = static_cast<T>(*other_it);
1299 : }
1300 : }
1301 :
1302 : template <size_t M, typename T>
1303 : size_t vector<M, T>::nnz() const
1304 : {
1305 : size_t counter = 0;
1306 :
1307 : const_iterator it = begin(), it_end = end();
1308 : for (; it != it_end; ++it)
1309 : {
1310 : if (*it != 0)
1311 : {
1312 : ++counter;
1313 : }
1314 : }
1315 :
1316 : return counter;
1317 : }
1318 :
1319 : template <size_t M, typename T>
1320 1 : double vector<M, T>::norm() const
1321 : {
1322 1 : double norm_v = 0.0;
1323 :
1324 1 : const_iterator it = begin(), it_end = end();
1325 9 : for (; it != it_end; ++it)
1326 : {
1327 4 : norm_v += *it * *it;
1328 : }
1329 :
1330 1 : return std::sqrt(norm_v);
1331 : }
1332 :
1333 : template <size_t M, typename T>
1334 : void vector<M, T>::set_random(int seed)
1335 : {
1336 : if (seed >= 0)
1337 : srand(seed);
1338 :
1339 : for (size_t i = 0; i < M; ++i)
1340 : {
1341 : const double fillValue = double(rand()) / double(RAND_MAX);
1342 : at(i) = -1.0 + 2.0 * fillValue;
1343 : }
1344 : }
1345 :
1346 : } // namespace vmml
1347 :
1348 : #endif
|